Publish Nerbus source snapshot and build documentation

This commit is contained in:
Nerbus Contributors committed 2026-10-17 18:56:29 +00:00
commit 76cccceca7
198 files changed
+338574

No files matched your search

+44
View File
@@ -0,0 +1,44 @@
# CSS files generated on startup
public/css/_theme-selector.scss
public/css/style.min.css
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directory
# Deployed apps should consider commenting this line out:
# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
node_modules
settings.json
.idea
*~
.DS_Store
package-lock.json
settings.json
.env
*.log
*.bak
*.backup*
node_modules/
tmp/
+1
View File
@@ -0,0 +1 @@
loglevel=silent
+30
View File
@@ -0,0 +1,30 @@
Copyright (c) 2019-2025, The Exor Community
Copyright (c) 2017, The Chaincoin Community
Copyright (c) 2015, Iquidus Technology
Copyright (c) 2015, Luke Williams
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Iquidus Technology nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+38
View File
@@ -0,0 +1,38 @@
# Nerbus Explorer
NRB block explorer based on [eIquidus](https://github.com/team-exor/eiquidus).
The running site is https://explorer.nerbus.com. This repository contains the
deployed application source, the Nerbus branding, mainnet identity check, and
network status integration. Production credentials and databases are excluded.
## Setup
Install a Node.js version supported by `package.json`, npm, and MongoDB 7.
```sh
npm ci
cp settings.nerbus.example.json settings.json
```
Edit `settings.json` with your private MongoDB and loopback NRB RPC credentials.
Use port 39441 and the Nerbus mainnet genesis configured in the example. Enable
`txindex=1` and `addressindex=1` on the node before indexing. Node startup is
performed separately by its operator. Start the explorer using its npm scripts
or the process manager described in `README.upstream.md`.
The interface and NRB branding are English. Both explorer and wallet verify the
expected genesis identity. When the node is unavailable, the explorer displays
network status rather than fabricated balances or blocks.
## Wallet network API
The optional bridge is maintained in the
[wallet repository](https://git.nerbus.com/nerbus/nerbus-wallet/src/branch/main/server).
It exposes only public address queries and signed transaction broadcast. It
does not hold private keys. Reverse-proxy `/wallet/v1` over HTTPS to its loopback
listener, following the included service configuration.
## License and attribution
See `LICENSE`, `README.upstream.md`, and the original source headers. The public
Nerbus repository starts from a snapshot of the deployed explorer source.
+1019
View File
File diff suppressed because it is too large. Load diff
+414
View File
@@ -0,0 +1,414 @@
NOTE: As of v1.100.0-bae4d50, it is no longer necessary to manually restart the explorer after updating, as long as you are using the built-in update script `npm run update-explorer`. All other manual updates such as `git pull` will still require a restart to the explorer after updating.
1.103.0 [February 02, 2025]
-Removed defunct exchange stex
-The default exchange has been changed to freiexchange
-Fixed an error in the peer sync when node has no port
-Added support for 3 top panel spacers
-Expired TLS/SSL certificates are now automatically updated as they are renewed from certbot
-Moved the database initialize call out of the instance code into the prestart script so that it is now only called once when you start the explorer even if you are running multiple cpus/threads
-The database connection function now uses the default connection string in the event a connection string is not supplied
-Fixed pm2 + forever detection for npm 9.7.2+
-The initialize_data_startup() function is now being called in the update_explorer script to ensure that new changes to the database structure are automaticaly run after the explorer code is updated
-All pages that auto-update data now also update the last updated date
-Updated the mongodb dependency to v6.x
-Minimum supported node.js version has changed to v16.20.1
-Added support for the Xeggex exchange
-Reindex now deletes data using the delete-database.js script which is much faster and more complete than the previous manual delete code used before
-The delete-database.js script now accepts a parameter that suppresses the delete prompt when being called from the resync process
-Reindex and normal block sync now reuse the same block sync code
-Removed the readline-sync dependency
-The ip address type masternode column has been renamed from Protocol to Network to prevent confusion with the other Protocol column used for the wallet protocol version number
-Moved claim address data into its own collection to make it easier to work with and preserve that data if necessary in the future without being cluttered into the address collection
-The index.js code has been refactored (reduced from 895 to 701 lines of code) which also cuts down the file size from 39KB to 26KB in size while still retaining the same functionality as before
-Footer icon images can no longer be highlighted
-Added ECMAScript Internationalization API support for older browsers
-The delete-database script now checks the claimaddresses collection for data and if at least 1 record exists, it will ask an additional question to see if you want to preserve that data or delete everything
-The prompt for deleting the database now happens after the locks have been properly checked
-jqPlot has been completely removed and replaced with chart.js on all remaining charts and graphs (richlist pie chart and market candlestick chart)
-chart.js was updated to v4.4.0 and later to v4.4.7
-chartjs-plugin-crosshair has been updated to v2.0.0
-Added 2 new small libraries to enable the chart.js candlestick chart: chartjs-chart-financial v0.1.1 and chartjs-adapter-luxon v1.3.1
-Removed defunct markets (bleutrade, crex24, txbit, unnamed)
-Improved the smoothness of opening and closing the claim address instructions
-jQuery has been updated to v3.7.1
-Luxon has been updated to v3.4.3
-Datatables has been updated to v1.13.6
-Font Awesome has been updated to v6.4.2 and all icons in the project have been updated to use the newest v6.x codes
-OverlayScrollbars has been updated to v2.3.2
-flag-icons (previously called flag-icon-css) has been updated to v6.11.1
-Updated the main style.scss file with better color support for the new datatable loading animation color
-Exor theme has been updated to v3.0.2 with a small fix to support the new datatable loading animation color
-Fixed some unreadable text for the sketchy theme on the markets page
-All external market apis have been normalized with a similar coding format, improved error handling with new wait times in between api calls to prevent abuse issues with sending too many requests too quickly
-All general market code has been reviewed and improved where necessary to help prevent sync issues
-Inactive markets are now removed from the markets collection on startup of the explorer to help prevent bloating the database
-The yobit api url has been changed to the new url
-The poloniex market has been updated to use the newest api
-The southxchange exchange trading link has been changed to the new url
-Fixed a bug with the freiexchange pair volume value when paired with LTC
-Added a default value of zero for many of the fields for each market in the event that the data returned for a particular field is not numeric
-The side menu toggle button is now an anchor tag instead of a div and no longer moves the search box when opening/closing the menu
-Added a fix for opening/closing the side menu when the browser window is zoomed in or out which didn't always work properly in all browsers earlier
-Javascript in the layout.pug has been moved around in an attempt to only load code into the client based on certain settings such as the type of menu (side or top) in order to slim down the loading of pages by not including unnecessary code
-Fixed a bug on the richlist page where the last updated date and logo spinning animation would fail to load if the distribution chart was disabled in the settings
-The /ext/getsummary api has been modified to only return the connection and block counts when necessary
-The getmasternodecount rpc api will no longer fetch data unless it is enabled in settings
-Added a crowdfunding section to the README
-Updated the README by splitting off the contact info into its own "Developer Contact" section and added a link to the "Premium Support" section
-Updated the README with new recommended versions for Node.js and MongoDB
-Updated the README with MongoDB install instructions for ubunutu 22.04 for the newest 7.x series of MongoDB
-Updated the README with some new options in the "Donations / Support Us" section
-Added an optional USD price panel
-Added an optional USD market cap panel
-Added USD price to the getsummary API
-Updated the mongoose dependency to v8.x along with some code updates to support new breaking changes
-Added a new default market sync option for averaging the prices across multiple supported exchanges
-Added a market sync option for fetching the market price directly from the coingecko api instead of calculating it via supported exchanges known to the explorer
-Added a new root setting option for default_coingecko_ids which allows presetting symbols to their associated internal coingecko id to help prevent matching to the wrong currency with same symbol via coingecko api calls
-Fixed an issue where the explorer would fail to start with an enabled exchange that had no defined trading pairs
-Added a coingecko api key option since the free "keyless" coingecko api will be deprecated in the near future (as of Feb 2024 or later)
-Updated the README to change the sample crontab from 2 to 5 minute intervals for the market sync since the coingecko api will soon force free users to the keyed api which only allows making 1 api call every 5 minutes without running out of credits for the month
-Updated the README with new urls to the Exor crowfunding / task list page
-Removed defunct exchange bittrex
-Fixed a bug that could sometimes render the sidebar in a funny position when the page loads
-Added support for a couple masternode list and count formats that do not have a separate fieldname for each value
-Masternode grid columns are now shown or hidden based on whether there is any data
-Fixed the spacing of masternode page columns after the table is loaded
-Fixed an issue that could crash the explorer when trying to use a masternode count value that is a single number (A single number masternode count is not valid or usable since it cannot differentiate the number of good and bad nodes, but the explorer will no longer crash when given this data)
-Added support for saving and displaying the algorithm used to mine a particular block for coins that support this feature and have the algorithm data stored in the raw block data
-Fixed a javascript error when resizing the browser window before the page finishes loading
-Added support for the Nonkyc exchange
-Added OHLCV chart support for the xeggex market
-Removed defunct exchange SouthXchange
-Updated the README with an updated yobit url
-Fixed a bug where the market sync could crash when calculating the USD price if the base pair of the markets_page.default_exchange.trading_pair value was not found in coingecko's vs_currencies list from https://api.coingecko.com/api/v3/simple/supported_vs_currencies (for example, using USDT as the default base pair)
-Added multiple captcha options for form submission on the claim address form (Supported captchas include Google reCaptcha v3 (score-based), Google reCaptcha v2 (checkbox and invisible) and hCaptcha ("Always Challenge" mode))
-Removed the ability to claim an address that has 0 transactions
-The "Claim" button is now disabled after submitting to help prevent double submissions on the claim address page
-Fixed the hCaptcha submission form so that it now clears itself after submitting the claim address form
-CSS is now only compiled when necessary on startup when new changes are detected
-Fixed a bug which could cache the top panel summary data when using the browser Back button and prevent it from updating properly until after reloading the page
-Added plugin support which allows extending the normal functionality of the explorer with new database collections, menus, pages and apis + open up a new url for data to be sent from the plugin to the explorer
-Locale strings are now loaded and shared out via the settings so there is generally no more need to explicitly include the locale.js file
-The locale object has been updated to `localization` within the explorer
-A number of new locale strings have been added and their values replaced with the locale string within the explorer
-Added plugin support verbiage and a link to the generic-snapshots crowdfunding task to the README
-Added the explorer version # to the header of all pages in a hidden element to make it easier to determine which commit a particular explorer is updated to even when the version # is removed from the powered by text in the footer
-Updated the polyfill script to v4.8.0
-Updated the bad-words dependency to v4.0.0 and resolved all breaking changes for the new version
-Improved logo panel spacing on small screens
-Fixed deprecation warnings for all applicable css themes
-The chartjs-plugin-crosshair chart plugin has been updated to v2.0.5 via a forked version that has a working sync feature which is now available as a new setting option for use with the network charts
-Added a new max_hours setting to display chart data for a certain number of hours instead of a fixed set of records which can help reveal holes in the sync process for the explorer and/or blockchain
-Added a number of new network chart settings to control display of the chart title, legend, a new vertical block line option, chart height, an option to force 2 charts to appear on their own row or beside each other, and an option to force a chart to take up all available space in the chart box without extra padding
-Added a new dependency chartjs-plugin-annotation v3.1.0 to display block lines in new hourly charts
-Fixed a missing document ready check on resizing the browser screen which caused some glitchy elements to not fix themselves as they should
-The block_parallel_tasks feature has been improved and fixed so that it is now safe to cancel (Ctrl+C) or kill (kill cmd not kill -9) the task and resume the sync later without missing transactions
-Updated the default block_parallel_tasks value to 8 threads which seems to be the sweet spot for any type of cpu
-Numerous improvements to the benchamark script to utilize new benchmark settings, auto-add credentials to the benchmark database, reuse the same sync code as the regular block sync instead of using a copy of the code and other small improvements
-Added a new cmd to run the benchmark script `npm run benchmark`
-Updated the README to include the new benchmark script instrutions + include multi-threaded sync as a feature
-The "Maximum call stack size exceeded" error is now handled internally by the block sync script in a way which will capture the error and re-launch the sync using a larger stack size and have the sync resume from where it left off
-Added a new option for sync.elastic_stack_size which is used to determine how much memory should be used to increase the stack size for the block sync after encountering the "Maximum call stack size exceeded" error
-Fixed an issue with the block sync when using more than 1 thread that could sometimes cause the flattened txes value in the coinstats database to be written incorrectly (Use `npm run reindex-txcount` to fix this issue without needing to reindex the entire database)
-Updated the benchmark script so that it can also benefit from being able to capture the "Maximum call stack size exceeded" error even though the timing will be off so it outputs a new warning in that scenario which instructs to run the benchmark again with a higher stack size to properly capture the benchmark time
-Removed the "Maximum call stack size exceeded" error notes from the "Known Issues" section of the README
-A number of functions have been rewritten to be more optimized and faster: calculate_total, is_unique, convert_to_satoshi, get_input_addresses, processVoutAddresses, prepare_vout, prepare_vin
-Txes are now written to database via bulk writes which helps improve the sync speed and also controls memory usage with batching to write data once a certain threshold is reached
-update_address function changed to update_addresses since it now bulk writes the addresses in batches to improve sync speed and also controls memory usage with batching to write data once a certain threshold is reached
-The syncLoop function has been completely removed from the project and replaced with async library loops or even normal "for" loops in some cases which greatly improves sync speeds over large batches of data
-Fixed an issue with the flattened count of txes that is saved to the coinstats collection which could save incorrectly when using more than 1 thread
-Fixed an issue with the block sync which caused an unwanted delay when syncing less blocks than the amount of threads used to sync the data
-Fixed an issue with vout data processing that could sometimes populate data out of order
-Added a new sync.batch_size setting used to determine how many records (txes, addresses, addresstxes) should be saved in a single database transaction
-Added a new wait_for_bulk_database_save setting used to increase the block sync speed at the cost of not returning any error msgs for data that failed to save
-get_input_addresses function no longer returns in the exports section of the explorer.js file since it is only referenced in that file
-Updated explorerspec tests to use the newest function changes for any tests that needed to be updated
1.102.0 [June 14, 2023]
-Added better support for NODE_ENV
-Added a new setting to redirect http to https
-Removed the "Full Setup Guide" section from the README
-Updated the README with new recommended versions for Node.js and MongoDB
-Updated the README with more text to make it more clear that EVM blockchains are not supported
-Updated the README with an extra step for exiting the mongo shell in the "Database Setup" section
-Updated the README by removing the "Quick Install Instructions" section title and now all install instructions are under the main Installation section
-Updated the README with new steps to the "Pre-Install" section for installing node.js and mongodb
-Updated the README with a new entry to the "Known Issues" section to explain the "Callback was already called" error msg
-Updated the README with a new entry to the "Known Issues" section that better explains the padLevels warning msgs when using the forever module
-Updated the README with alternate instructions to the "Manually Link TLS/SSL Certificates to the Explorer" section which better explain which method should be used depending on whether the explorer is running on port 80 for http traffic or not
-Added an rpc cmd queue
-Fixed an issue that caused 2 or more masternodes created in the same transaction to be treated as the same entry
-The "Powered By" footer text is now configurable
-Better handling of null market data
-The mongoose and mongodb dependencies have been updated to the most recent versions in package.json which required fixing many breaking changes to a number of files in the explorer
-Fixed a few Deprecation Warning msgs for the Flatly, Litera and Solar themes
-Added better quote support for the coin name and symbol settings
-Added support for handling orphaned blocks along with a new optional page to display them
-The coinbase address now updates sent totals from POS rewards and other transactions that have vout but no vin addresses
-The block and transaction pages now display a warning when viewing an orphaned block or tx
-Fixed the incorrect confirmations value in the gettx api
-Fixed the "DeprecationWarning: Mongoose: the `strictQuery` option will be switched back to `false` by default in Mongoose 7" warning msg from newer mongoose versions
-Added new settings to improve the network chart precision for small decimal values like 0.00028363 which were previously being rounded to 0
-Removed the jstransformer-markdown-it dependency
-Added new settings to allow hiding the port number on the network page tables
-Fixed the footer width calculations
-Improvements to the core layout including new scrollbars on the mobile menu items when there are too many items to fit on the screen at once
-Added side menu support
-Fixed the peer sync for addresses without country data
-Fixed a divide by zero error when calculating market change
-Added support for the Unnamed exchange
-Added support for the Txbit exchange
-Better handling of stop/kill sync processes (The SIGINT and SIGTERM signals are now being caught and handled in the sync.js file so that most options for syncing blocks, markets, peers, masternodes, etc. are now being gracefully shut down instead of killed in the middle of the process. This should help prevent data anomalies when you need to stop or kill a sync process)
-Added support for vin/vout hashes inside an array
1.101.0 [July 09, 2022]
-Locale string tx_hash was changed from "Hash" to "Tx Hash" to be clearer about which Hash it refers to
-TXid was renamed to "Tx Hash" throughout the site
-Removed the coin name from the tx hash label on the transaction page
-Removed the coin name from the block hash label on the block page and changed the text "block" to "Block Hash"
-The header_logo.png was renamed to header-logo.png
-Added 2 optional arguments to the update script to update the explorer code only (`npm run update-explorer "explorer-only"`) and another option to update outdated dependencies only (`npm run update-explorer "dependencies-only"`)
-Added a custom.js file that can be used to add custom javascript code without affecting the ability to do a `git pull` or `npm run update-explorer` update
-Added "copy to clipboard" buttons to the network addnode tables
-Network addnode table data no longer wraps onto multiple lines when the data cannot fit on the screen
-Fixed a bug which caused the error page to not show a proper page title
-Fixed a bug which caused the locking mechanism to fail on non-windows computers when the explorer is installed to a directory that has a space character somewhere in the absolute path
-The update_explorer.js script has been improved with better spacing and the ability to restart the explorer automatically to ensure new changes take effect immidiately (works with npm start, pm2 and forever)
-The code to compile scss to css has been moved from the prestart script into its own compile_css.js script which is now called from the update-explorer.js script to apply css changes after update
-The cluster code now handles a custom restart msg which is used to restart the explorer from the update explorer process
-Pm2 and Forever are now referenced by the name 'explorer' instead of ./bin/instance or ./bin/cluster
-Added reload/restart scripts to the package.json for pm2 and forever
-Pm2 and forever now write a pid file to the tmp directory when started. NOTE: Forever is now started from the prestart script due to a bug in forever that prevents the pid from being written to a different directory without the absolute path
-Fixed a bug which caused the prestart script to be run twice when starting the explorer with `npm start`
-The cluster code now accepts a numeric argument to force a specific number of instances to be loaded
-The `npm run start-instance` cmd now loads using the cluster code with a single instance
-The is_locked function now accepts an optional 'silent' argument to prevent displaying msgs while checking for pid/lock files
-Added a port_filter setting to the 3 network_page tables which allows showing only results from peers on the selected port
-Added a hide_protocols setting to the 3 network_page tables which allows hiding results from peers on the selected protocols
-Added a Port column to the data table on the Network page Connections tab
-The data table on the Network page Connections tab is now sortable
-The peer sync now refreshes data for peers that existed since last sync
-Adding and updating peers now displays the port # in the log output
-The /ext/getnetworkpeers api is now sorted by ip4/ip6, address and port which also means all data on the Network page is sorted this way by default as well
-Improved loading speed of the network page by combining 3 separate database calls into 1
-Added support for the Dex-Trade exchange
-Added support for the FreiExchange/FreiXLite exchange (this exchange has 2 separate sites using the same api, so new functionality was added to the explorer to handle alt markets like this with an alt market name, alt logo, market url and an "isAlt" function to determine if the alt name/logo should be used)
-Support was added for the getblockchaininfo rpc cmd which now allows the coin supply to be populated via this function
-The network difficulty chart now supports 2 datasets: POW and POS
-Fixed a bug with the network difficulty chart where it would fail to populate if the shared_pages.difficulty setting was 'Hybrid'
-NetworkHistory.difficulty field was renamed to difficulty_pow and a new difficulty_pos field was added
-The shared_pages.page_header.network_charts.difficulty_chart.line_color setting was renamed to pow_line_color
-The shared_pages.page_header.network_charts.difficulty_chart.fill_color setting was renamed to pow_fill_color
-The favicon functionality was updated so that instead of using a single file for the favicon, there are now 4 size options for a more modern favicon experience
-Fixed a bug which did not properly handle certain special characters in the mongo username/password such as % or @ for example
-Updated the README with details of the "bind EACCES" error msg that can appear when you try to run the explorer on a port number lower than 1024
-Updated the README with instructions for using the newer node.js production flag (--only=prod) instead of the old flag (--production)
-Added pm2 and forever to the dev dependencies list to help prevent package.json from being automatically updated/changed in production which could make `git pull` fail due to the changes
-Both dependencies and dev dependencies sections have been sorted alphabetically to help prevent auto package.json changes
-The custom user-agent strings for http requests have all been removed
-Fixed an issue with the crex24 market chart that could cause it to be overpopulated with data and therefore unreadable/unusable
1.100.0 [May 29, 2022]
-Added a custom.scss file that can be used to add custom css changes without affecting the ability to do a git pull update
-Added new update script to A) grab the latest code form github, B) update all dependencies, and C) run the database initialize function to ensure new changes take effect immidiately
-freegeoip.app now requires an api key so the peer sync has been updated to use reallyfreegeoip.org instead
-Added extra error checking to the peer sync so that it will error out when the geolocation service does not return a proper object
-Added locks to all sync processes (blocks, markets, peers, masternodes) as well as "create backup", "restore backup" and "delete database" functions. This helps prevent problems with syncing data while a backup is in progress for example
-The code to initialize certain database collections on startup was moved into database.js and is now called from restore_backup.js and delete_database.js. This effectively allows the database to be deleted or restored to a completely different backup while the explorer is still running
-Lock functions (create_lock, remove_lock, is_locked) were moved into explorer.js for better reusability and rewriten to be synchronous
-is_locked function now accepts an array of lock files to be able to check for multiple locks in a single call
-remove_sync_message() function was moved into database.js so that restore_backup.js and delete_database.js can also check for and remove the sync msg if it exists
-Rewrote a number of internal scripts to allow for better cross-platform support (Windown, MacOS, Linux)
-Backup and Restore scripts now use mongo's own encryption instead of tar.gz by default. Older tar.gz backups can still be restored as long as the tar.gz suffix is explicitly added
-Backup and Restore scripts now support connecting to remote database based on the mongo details in settings.json
-Added a link to exchange on markets page
-Added the current git commit id to end of explorer version
-Fixed the format of ipv6 addnodes on the network page
-Added a Hashrate chart to the page header
-Added a Difficulty chart to the page header
-Improved the Index/Update sync feature (Shifted some of the code around to be run in a better order)
-update_heavy has been moved into a proper callback function which is now only called for index and reindex syncs right near the end of the process instead of at the beginning
-Added some tweaks and improvements to the Reindex sync feature (Added an "Are you sure" prompt before starting the reindex, All necessary coin stat data is cleared before starting, More and better messages about what is being done during the process, Shifted some of the code around to be run in a better order)
-Added unique page titles for each individual page
-Added code to prevent caching of local css files
-Bootstrap was upgraded to latest version (v5.1.3) which required tons of changes to the UI. Many little UI problems have been resolved
-Bootswatchs themes have all been upgraded to support bootstrap v5.1.3 + 4 new themes were added (Morph, Quartz, Vapor and Zephyr)
-Exor theme update to v3.0.0 with support for bootstrap v5.1.3
-Many layout and UI improvements such as more consistent hover effects on most tables and more readable text across all themes
-All libraries have been updated and load a CDN url instead of local file where applicable
-Codebase was updated so that Node.js must be updated to at least v14.13.1 to fix breaking errors in a few of the updated dependencies
-Added an optional block_start parameter to check mode
-Check mode no longer updates the last block height
-Added a .npmrc file for cleaner npm error msgs
-Added new npm scripts to make syncing and running other explorer tasks easier, without needing to remember longer command syntax
-Added support for reading scriptPubKey.address
-Added Southxchange exchange to markets
-Added a new setting to decode tx OP_RETURN values
-Market sync now sets the last USD price based on the default market pair even if it is not BTC
-Removed the coindesk api which was only really useful for getting the USD price of BTC
-Added a couple coingecko apis which are used to get the current USD value of the default market pair
-Fixed issues loading site in safari browser (Safari behaves differently than other browsers and seems to require the url prefix to be present when loading external libraries to prevent CORS errors)
-Many blockchains allow you to use addnodes without a port # and it will assume the default port internally, but the explorer was failing to parse these peers because it was expecting a port. This is now fixed and will display the peer data without a port in these cases
-Added support for newer (deterministic) Dash masternode format
-More graceful shutdown of node cluster on 'npm stop' with better cleanup of resources on exit
-Added new stop_explorer.sh script which looks up the explorer port # via settings file and closes the application running on that port # instead of saving and killing the process by pid as it did before
-Added support for pm2 and forever using 'npm run start-pm2' and 'npm run start-forever' respectively
-pm2 is automatically installed when starting with 'npm run start-pm2' if it is not already installed
-forever is automatically installed when starting with 'npm run start-forever' if it is not already installed
-Reorganized the structure and order of calls within the /ext/getsummary api to allow for returning just the connection and block counts for pages that have show_panels set to false
-Combined two script sections into one on the address page
-Changed the shorthand $(function() into $(document).ready() for consistency on the claim address page
-Added an api page setting to hide/show logo
-All pages (including the reward and error pages) were updated to include options for displaying a configurable page header with title, image, description and in some cases a last updated date
-The error page was restructured slightly to display a different description based on the type of error (page not found error vs problem loading page error)
-Added new setting options to the `shared_pages` setting for `page_title_image` which allows changing the page title image displayed on applicable pages and also determines whether it uses a flip/spin animation or not
-Added a collection of new `page_header` settings to all pages that control displaying the new page title + image + description and also moved the last updated date from applicable pages into this section as well
-Existing `show_last_updated` settings that were moved a level deeper into the `page_header` have been automatically mapped to the new setting location upon statup to help older installs to work better out-of-the-box
-Locale strings now support replacement text such as {1} and {2} that get automatically replaced with proper values when loaded to allow for locale strings that support dynamic text
-Fixed an issue with too much empty space in the page header (especially in mobile and tablet modes) when `show_panels` was set to false on any page
-Removed unused css class 'loading'
-Added new settings to hide/show panels on each page
-Added a new `shared_pages.page_header.search.position` setting that determines where the search bar is located (valid options include the old 'below-header' and the new 'inside-header' options)
-`shared_pages.page_header.show_search` setting has been re-mapped to `shared_pages.page_header.search.enabled`
-Updated the search placeholder locale text
-Changed the Explorer menu item icon from a magnifying glass to a cubes/blocks icon
-Updated css rules to fix some small glitches and allow the new 'inside-header' search option to function
-Fixed a glitch with header-panel height not working on some browsers
-Added a new prestart npm script
-Fixed + formatted date/time values across entire site using Luxon
-Added new date/time settings for display format, timezone (utc or local) and an option to enable alternate timezone tooltips
-All markets now return Trade History timestamp values as unix timestamp values formatted in seconds
-Added TLS/SSL support
-Added new address_page.enable_hidden_address_view setting which controls whether the special hidden_address address page can be viewed
-Added new address_page.enable_unknown_address_view setting which controls whether the special unknown_address address page can be viewed
-Permanently disabled route to special coinbase address
-Added better unique checks for vout/vin
-Added full zksnarks tx support
-Special addresses are now always omitted from the richlist
-Improved restore backup script
-Improved delete database script
-Added support for bitcoin P2PK scripts/txes
-Added a tx_type field to the tx model which is typically null for "normal" transaction types, but can also display 'p2pk' for bitcoin txes which require addtional encoding to reveal the P2PKH address as well as 'zksnarks' for transactions with hidden sender or receiver data
-Additional fixes for how data is displayed when a valid wallet address cannot be found
-Added some small updates to how zksnarks transactions display hidden sender/receiver data
-Went through all files and did a bit of a code cleanup
-Added homepage screenshot to readme
-Fixed the stex 24h stats volume column which was displaying btc volume
-Added btc volume column to 24 stats for stex market
-Update altmarkets api to v2
-Improved the display of the market page so that as long as one section has data (stats, buys, sells, trade history) the page will load properly even if it's only one section that isn't blank. Previously it would display an error if just one section was blank.
-Added the coin name beside the market pages volume header column in the 24h stats section
-Fixed a bug that was displaying an error when the summary value from the 24h stats section was supplied but was a blank string or '-' character
-Better success/error message during market sync
-Small readme formatting changes
-Added ZWSP to prevent address copy/paste issues
1.99.0 [February 05, 2021]
-Added new sync option for reindex-last to rescan and flatten the last blockindex value for faster access
-Added new sync option for reindex-txcount to rescan and flatten the tx count value for faster access
-Added new sync option for reindex-rich to clear and recreate the richlist data
-Improved loading of settings including warning of missing and/or invalid settings and the ability to load the explorer using defaults without a settings.json file
-Restructured the settings.json.template and settings.js files with better groupings
-Added better comments for improved explanations of all settings
-Better handling of page length options on all datatables; Page length options are now configurable and also only display options based on limits set by certain items_per_page and max_items_per_query settings
-Markets have been extended to support unlimited trading pairs for each exchange
-Richlist page now allows better separation of the top list(s) and the wealth distribution table and chart (you can now hide or show sections as desired)
-Richlist page now allows for better burned coin support (Hide burned coin addresses from lists and totals even when the burned coin amounts are still included in the total coin supply value)
-Block page now only displays the raw block link if the api_page.public_apis.rpc.getblock.enabled settings is set to true
-Transaction page now only displays the raw tx link if the api_page.public_apis.rpc.getrawtransaction.enabled setting is set to true
-Rate limiting class has been made global and is now used to limit market requests
-getnetworkhashps rpc call now returns a '-' if shared_pages.show_hashrate is not set to true
-Searching for unsycned blocks/txs no longer saves the data locally but instead still shows the data on screen. This helps prevent syncing data out-of-order (This eliminates the need for db_index.pid which has been removed)
-Coin supply is now always taken from the stats collection database instead of from the wallet via rpc command in all cases except when syncing
-Added new social_links setting to allow adding as many custom links as desired including the ability to display as image or fontawesome icon
-Removed old hardcoded settings for twitter, facebook, google+, bitcointalk, github, slack, discord, telegram, reddit, youtube and custom website link
-Removed unnecessary includes for address_history.pug, net_addnodes.pug, net_list.pug, rl_balance.pug, rl_received.pug and restored code in place of include
-Renamed /ext/connections to /ext/getnetworkpeers and added it to list of public apis on the /info page
-/ext/getsummary now only returns the online and offline masternode counts if the getmasternodecount api is available and enabled
-Renamed /ext/summary to /ext/getsummary and added it to list of public apis on the /info page
-Added /ext/getaddresstxs to the list of public apis on the /info page + updated the return data so that it returns a named object array for public api for better readability and still returns the same array list for internal datatable use
-Updated /ext/getlasttxs so that it returns a named object array for public api for better readability and still returns the same array list for internal datatable use
-Added new configurable settings to allow displaying a "last updated date" timestamp for: index, reward, masternode, movement, network, richlist and market pages
-Pages disabled via settings are now completely disabled on the front-end whereas before some were still accessible via exact url
-Added a new api /ext/getmasternoderewards which returns a list of masternode reward transactions for a single address since a particular block height
-Added a new api /ext/getmasternoderewardstotal which returns the total masternode rewards earned for a single address since a particular block height
-/ext/getbasicstats api now only includes the masternode count if the getmasternodecount api is available and enabled
-Added a new "Masternodes" page which displays the current list of masternodes on the network
-Exor theme updated to v2.0.0 with support for bootstrap v4.5.3
-All coind + extended public api calls can now be enabled/disabled individually via settings
-Added a new setting to display an alternate "header logo" in the page header
-Added a new setting for displaying a coin logo image top panel
-Added a new setting for displaying a 'Market Cap' top panel
-Added 16x16 logo images to markets
-Show spinning loading icons in top panels before data is loaded
-Better reusability of rl_labels.pug
-Added new market settings for accessing multiple markets (Turn markets header menu into a dropdown with multiple market selection and/or enable a multi-market select box on all market pages)
-Fixed and added better tooltips where applicable
-Wallet api security is now dynamically controlled by the new api_cmds settings
-Restored the jasmine testing functionality along with some sample tests for debugging purposes
-Added new settings for changing header/footer/thead background color via bootstrap css classes
-All unnecessary/unused data is now filtered from ajax-enabled datatables to make ajax calls cleaner and easier to read
-Updated JQuery to v3.5.1
-Updated Bootstrap to v4.5.3
-Updated DataTables to v1.10.22
-Updated FontAwesome to v5.15.1
-Updated Chart.js to v2.9.4
-Updated flag-icon-css to v3.5.0
-All scripts now load minified
-Removed unused/unnecessary scripts (moment.js and some jqPlot plugins)
-Scripts that are not used on every page are now only loaded on pages where they are needed (jqPlot, Chart.js and flag-icon-css)
-Default website language to English
-Enable unicode support
-Removed unused images
-Many internal structure changes to make the code cleaner and easier to find and read
-Reward page rewritten to support Chart.js v2.9.4
-All bootswatch themes updated to newest versions (support for bootstrap v4.5.3)
-Added sass support
-Added new settings for sticky header/footer support
-Added better error checking for invalid markets
-Added the ability to lookup unsynced transactions (search for txid that has not yet been synced)
-Fixed a bug in the index sync to prevent gaps in the block data
-Added a new setting to determine how many blocks to sync before saving stats
-Added new settings to customize footer height + social link sizes
-Improved long index sync warning functionality
-Enabled responsive/mobile support
-format_unixtime function is now used to format all date values
-Fixed all "collection.count is deprecated" warnings
-Fixed startup error ERR_INVALID_ARG_TYPE when using node.js 14+
-Greatly improved and simplified markets functionality, including generic markets page that is consumed by all markets now
-Added last_txs to /ext/getaddress api
-Updated jqPlot to v1.0.9.d96a669
-Network peers list now displays flag icons for country data
-Explorer name and version now displayed in footer
-Added the ability to index blocks in parallel for dramatic speed increases during blockchain sync (there is a known issue with this feature that can cause historical balance data to be out-of-sync)
-Added new claim address feature with bad word filters which allows anyone to set custom display names for wallet addresses that they own using the 'Sign Message' feature from their local wallet (Claimed addresses now replace actual wallet addresses across all pages of the site)
-Added new use_rpc setting to allow explorer to get wallet data from rpc directly or still consume the public apis as before
-All numerical values now use a separate CSS class to display digits after decimal place
-Added historical balance to address history data
-Peers sync now uses freegeoip.app for IP geolocation
-Added new Network tab with info to easily get addnode data for Wallets
-Added new /ext/gettx api
-Fixed a number of cluster issues that broke support for newer node versions
-Fixed a memory overflow error when indexing 1000s of TXs
-Added support for Altmarkets.io exchange
-Added full address history support as opposed to only displaying top x records
-Added ipv6 support
-All api end-points now return text values with HTTP header content-type 'text/plain'
-Removed defunct markets (ccex, coinexchange, cryptopia, cryptsy, empoex)
-Replaced deprecated 'request' dependency with 'postman-request'
-Added support for Crex24 exchange
-Added partial Zcash/zk-SNARKs private tx support (90% complete)
-Added support for customizing daemon api cmds
-Fixed incorrect 'Wealth Distribution' total percent value
-Added support for omitting 'burned coin' addresses from the rich list
1.0.1 [June 7, 2019]
-Added stex.com market support
-Added a new public api /ext/getbasicstats
-Fixed all depreciation warnings regarding mongo db.update statements
-Updated outdated mongodb and mongoose references
1.0.0 [May 27, 2019]
-Initial release
+1308
View File
File diff suppressed because it is too large. Load diff
Executable
+88
View File
@@ -0,0 +1,88 @@
var cluster = require('cluster');
if (cluster.isMaster) {
const isWinOS = process.platform == 'win32';
const instances = (process.argv[2] != null && process.argv[2] != '' && !isNaN(process.argv[2]) && Number.isInteger(parseFloat(process.argv[2])) ? parseInt(process.argv[2]) : require('os').cpus().length);
console.log('Starting cluster with pid: ' + process.pid);
function startWorkers() {
// create worker instances
for (var i = 0; i < instances; i += 1)
cluster.fork();
}
function killAllWorkers(isRestart) {
// send kill cmd to all workers
for (var id in cluster.workers) {
console.log('Worker (' + id + ') shutting down...');
if (!isWinOS || isRestart) {
// only kill the worker if not on windows (otherwise an error is displayed) or if the cluster is being restarted
process.kill(cluster.workers[id]['process']['pid'], 'SIGINT');
}
}
}
function waitForWorkerShutdown(isRestart) {
if (Object.keys(cluster.workers).length > 0) {
// continue waiting since worker threads are still open
setTimeout(waitForWorkerShutdown, 100, isRestart);
} else {
// all worker threads have closed
// check if the cluster process should stop or if the workers should be restarted
if (isRestart) {
// start new worker threads
startWorkers();
} else {
// exit the master process
if (isWinOS) {
// command line in windows doesn't seem to release itself
// show a message that the app has finished
console.log('The application is now safe to close');
}
process.exit(0);
}
}
}
// ensure workers exit cleanly
process.on('SIGINT', () => {
console.log('Cluster shutting down..');
// send kill cmd to all workers
killAllWorkers(false);
// wait for workers to stop
waitForWorkerShutdown(false);
});
startWorkers();
// listen for dying workers
cluster.on('exit', function (worker, code, signal) {
if (worker['process']['exitCode'] === 0) {
console.log('Worker (' + worker['id'] + ') shutdown complete');
} else if (signal != 'SIGINT' && worker['process']['exitCode'] !== 0 && worker['process']['exitCode'] !== 999 && worker.exitedAfterDisconnect !== true) {
console.log('Cluster restarting...');
cluster.fork();
}
});
// listen for the restart cmd
cluster.on('message', function (data, msg) {
// check if this was the restart cmd
if (msg != null && msg == 'restart') {
console.log('Cluster restarting..');
// send kill cmd to all workers
killAllWorkers(true);
// wait for workers to stop
waitForWorkerShutdown(true);
}
});
} else
require('./instance');
Executable
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env node
var debug = require('debug')('explorer');
var settings = require('../lib/settings');
var db = require('../lib/database');
var app = require('../app');
app.set('port', process.env.PORT || settings.webserver.port);
db.connect(null, function() {
var server = app.listen(app.get('port'), '127.0.0.1', function() {
debug('Express server listening on port ' + server.address().port);
});
process.on('SIGINT', () => {
server.close(() => {
var mongoose = require('mongoose');
mongoose.connection.close(false).then(() => {
// close the main process now that all http and database connections have closed
process.exit(0);
}).catch((err) => {
console.log(err);
process.exit(1);
});
});
});
});
+116
View File
@@ -0,0 +1,116 @@
const request = require('postman-request');
const base_url = 'https://api.coingecko.com/api/v3/';
const Decimal = require('decimal.js');
function get_coin_list(api_key, cb) {
request({ uri: base_url + 'coins/list?include_platform=false' + (api_key == null || api_key == '' ? '' : '&x_cg_demo_api_key=' + api_key), json: true}, function (error, response, body) {
if (error)
return cb(error, []);
else if (body == null || body == '' || typeof body !== 'object')
return cb('No data returned', []);
else if (body['status'] != null && body['status']['error_message'] != null && body['status']['error_message'] != '')
return cb(body['status']['error_message'], []);
else
return cb(null, body);
});
}
function get_simple_price(id, currency, market_array, api_key, cb) {
request({ uri: base_url + `simple/price?ids=${id.toLowerCase()}&vs_currencies=usd${currency == null || currency == '' ? '' : `,${currency}`}` + (api_key == null || api_key == '' ? '' : '&x_cg_demo_api_key=' + api_key), json: true}, function (error, response, body) {
if (error)
return cb(error, new Decimal('0'), new Decimal('0'));
else if (body == null || body == '' || typeof body !== 'object')
return cb('No data returned', new Decimal('0'), new Decimal('0'));
else if (body['status'] != null && body['status']['error_message'] != null && body['status']['error_message'] != '')
return cb(body['status']['error_message'], new Decimal('0'), new Decimal('0'));
else {
try {
if (market_array != null) {
// multiple currencies need to be combined before return
let last_price = new Decimal('0');
let last_usd_price = new Decimal('0');
let counter = 0;
let api_market = null;
// check if the currency variable is set
if (currency != null && currency != '') {
// find the market currency in the market_array
const base_index = market_array.findIndex(p => p.currency.toLowerCase() == currency.toLowerCase());
// check if the currency is found in the market_array
if (base_index > -1) {
// find the api market data row
api_market = body[market_array[base_index].coingecko_id.toLowerCase()];
}
}
// loop through all api object keys
Object.keys(body).forEach(function(key, index, map) {
const market_index = market_array.findIndex(p => p.coingecko_id.toLowerCase() == key.toLowerCase());
// check if the currency is found in the market_array
if (market_index > -1) {
// determine if the api already returned the market price
if (currency != null && currency != '' && body[key][currency.toLowerCase()] != null) {
// calculate the market price
last_price = last_price.add(new Decimal(market_array[market_index].last_price.toString()).mul(new Decimal((currency == null || currency == '' ? new Decimal('0') : new Decimal(body[key][currency.toLowerCase()].toString())))));
} else {
// check if the market currency exists in the api data
if (api_market != null) {
// calculate the currency ratio
const ratio = new Decimal(api_market['usd'].toString()).div(body[key]['usd'].toString());
// calculate the market price
last_price = last_price.add(new Decimal(market_array[market_index].last_price.toString()).div(ratio));
}
}
// calculate the usd price
last_usd_price = last_usd_price.add(new Decimal(market_array[market_index].last_price.toString()).mul(body[key]['usd'].toString()));
counter++;
}
});
// check if the counter is greater than 0
if (counter > 0) {
// average the market and usd prices
last_price = last_price.div(counter.toString());
last_usd_price = last_usd_price.div(counter.toString());
}
return cb(null, last_price, last_usd_price);
} else {
// single currency
return cb(null, (currency == null || currency == '' ? new Decimal('0') : new Decimal(body[id.toLowerCase()][currency.toLowerCase()].toString())), new Decimal(body[id.toLowerCase()]['usd'].toString()));
}
} catch(err) {
return cb('Received unexpected API data response', new Decimal('0'), new Decimal('0'));
}
}
});
}
module.exports = {
get_coin_data: function (api_key, cb) {
get_coin_list(api_key, function (err, coin_list) {
return cb(err, coin_list);
});
},
get_market_prices: function (id, currency, api_key, cb) {
get_simple_price(id, currency, null, api_key, function (err, last_price, last_usd) {
if (last_price == null)
console.log(`Error: "${currency}" is not a valid coingecko api currency`);
return cb(err, last_price, last_usd);
});
},
get_avg_market_prices: function (id, currency, market_array, api_key, cb) {
get_simple_price(id, currency, market_array, api_key, function (err, last_price, last_usd) {
if (last_price == null)
console.log(`Error: "${currency}" is not a valid coingecko api currency`);
return cb(err, last_price, last_usd);
});
}
};
+1063
View File
File diff suppressed because it is too large. Load diff
+2334
View File
File diff suppressed because it is too large. Load diff
+1451
View File
File diff suppressed because it is too large. Load diff
+171
View File
@@ -0,0 +1,171 @@
var http = require('http'),
https = require('https');
var Client = function(opts) {
this.opts = opts || {};
this.http = this.opts.ssl ? https : http;
};
Client.prototype.call = function(method, params, callback, errback, path) {
var time = Date.now();
var requestJSON;
if (Array.isArray(method)) {
// multiple rpc batch call
requestJSON = [];
method.forEach(function(batchCall, i) {
requestJSON.push({
id: time + '-' + i,
method: batchCall.method,
params: batchCall.params
});
});
} else {
// single rpc call
requestJSON = {
id: time,
method: method,
params: params
};
}
// first we encode the request into JSON
var requestJSON = JSON.stringify(requestJSON);
// prepare request options
var requestOptions = {
host: this.opts.host,
port: this.opts.port,
method: 'POST',
path: path || '/',
headers: {
'Host': this.opts.host,
'Content-Length': requestJSON.length
},
agent: false,
rejectUnauthorized: this.opts.ssl && this.opts.sslStrict !== false
};
if (this.opts.ssl && this.opts.sslCa) {
requestOptions.ca = this.opts.sslCa;
}
// use HTTP auth if user and password set
if (this.opts.username && this.opts.password)
requestOptions.auth = this.opts.username + ':' + this.opts.password;
// now make a request to the server
var cbCalled = false
var request = this.http.request(requestOptions);
// start request timeout timer
var reqTimeout = setTimeout(function() {
if (cbCalled)
return;
cbCalled = true;
request.abort();
var err = new Error('ETIMEDOUT');
err.code = 'ETIMEDOUT';
errback(err);
}, this.opts.timeout || 30000);
// set additional timeout on socket in case of remote freeze after sending headers
request.setTimeout(this.opts.timeout || 30000, function() {
if (cbCalled)
return;
cbCalled = true;
request.abort();
var err = new Error('ESOCKETTIMEDOUT');
err.code = 'ESOCKETTIMEDOUT';
errback(err);
});
request.on('error', function(err) {
if (cbCalled)
return;
cbCalled = true;
clearTimeout(reqTimeout);
errback(err);
});
request.on('response', function(response) {
clearTimeout(reqTimeout);
// we need to buffer the response chunks in a nonblocking way
var buffer = '';
response.on('data', function(chunk) {
buffer = buffer + chunk;
});
// when all the responses are finished, we decode the JSON and
// depending on whether it's got a result or an error, we call
// emitSuccess or emitError on the promise.
response.on('end', function() {
var err;
if (cbCalled)
return;
cbCalled = true;
try {
var decoded = JSON.parse(buffer);
} catch (e) {
if (response.statusCode !== 200) {
err = new Error('Invalid params, response status code: ' + response.statusCode);
err.code = -32602;
errback(err);
} else {
err = new Error('Problem parsing JSON response from server');
err.code = -32603;
errback(err);
}
return;
}
if (!Array.isArray(decoded))
decoded = [decoded];
// iterate over each response, normally there will be just one
// unless a batch rpc call response is being processed
decoded.forEach(function(decodedResponse, i) {
if (decodedResponse.hasOwnProperty('error') && decodedResponse.error != null) {
if (errback) {
err = new Error(decodedResponse.error.message || '');
if (decodedResponse.error.code)
err.code = decodedResponse.error.code;
errback(err);
}
} else if (decodedResponse.hasOwnProperty('result')) {
if (callback)
callback(decodedResponse.result, response.headers);
} else {
if (errback) {
err = new Error(decodedResponse.error.message || '');
if (decodedResponse.error.code)
err.code = decodedResponse.error.code;
errback(err);
}
}
});
});
});
request.end(requestJSON);
};
module.exports.Client = Client;
+301
View File
@@ -0,0 +1,301 @@
/**
* The Locale Module reads the locale settings and provides
* this information to the other modules
*/
exports.localization = {
// global
"difficulty": "Difficulty",
"network": "Network",
"masternodecount": "Masternodes",
"height": "Height",
"timestamp": "Timestamp",
"size": "Size",
"transactions": "Transactions",
"total_sent": "Total Sent",
"total_received": "Total Received",
"confirmations": "Confirmations",
"total": "Total",
"total_top_100": "Top 1-100 Total",
"bits": "Bits",
"nonce": "Nonce",
"new_coins": "New Coins",
"proof_of_stake": "PoS",
"hidden_address": "Hidden Address",
"hidden_sender": "Hidden Sender",
"hidden_recipient": "Hidden Recipient",
"unknown_address": "Unknown Address",
"unknown_sender": "Unknown Sender",
"unknown_recipient": "Unknown Recipient",
"last_updated": "Last Updated",
"initial_index_alert": "Blockchain data is currently being synchronized. You may browse the site during this time, but keep in mind that data may not yet be fully accurate and some functionality may not work until synchronization is complete.",
"please_wait": "Please wait",
"creating_initial_entry": "Creating initial {1} entry",
"entry_created_successfully": "Initial {1} entry for {2} created successfully",
"method_disabled": "This method is disabled",
"compiling_css": "Compiling CSS",
"installing_module": "Installing {1} module",
"restoring_backup": "Restoring backup",
"extracting_backup_files": "Extracting backup files",
"explorer_shutting_down": "Explorer shutting down",
"initializing_database": "Initializing database",
"downloading_newest_explorer_code": "Downloading newest explorer code",
"check_outdated_packages": "Checking for outdated packages",
"updating_explorer_packages": "Updating out-of-date explorer packages",
"checking_webserver_running": "Checking if webserver is running",
"reloading_explorer": "Reloading the explorer",
"email_sent_successfully": "Email sent successfully",
"check_console": "Check your console",
"process_aborted": "Process aborted",
"nothing_was_deleted": "Nothing was deleted",
"nothing_was_restored": "Nothing was restored",
// prompts
"are_you_sure": "Are you sure you want to do this? [y/n]",
"short_yes": "y",
"long_yes": "yes",
// menu items
"menu_explorer": "Explorer",
"menu_api": "API",
"menu_markets": "Markets",
"menu_richlist": "Rich List",
"menu_reward": "Reward",
"menu_movement": "Movement",
"menu_node": "Nodes",
"menu_network": "Network",
"menu_claim_address": "Claim Address",
"menu_orphans": "Orphaned Blocks",
// explorer view
"ex_title": "{1} Block Explorer",
"ex_description": "A listing of all verified {1} transactions",
"ex_search_title": "Search",
"ex_search_button": "Search",
"ex_search_message": "Search by block height, block hash, tx hash or address",
"ex_error": "Error",
"ex_warning": "Warning",
"ex_search_error": "Search found no results.",
"ex_latest_transactions": "Latest Transactions",
"ex_summary": "Block Summary",
"ex_supply": "Coin Supply",
"ex_block": "Block",
// transaction view
"tx_title": "{1} Transaction Details",
"tx_description": "Viewing tx data from {1} block # {2}",
"tx_block_hash": "Block Hash",
"tx_recipients": "Recipients",
"tx_contributors": "Contributor(s)",
"tx_hash": "Tx Hash",
"tx_address": "Address",
"tx_nonstandard": "NONSTANDARD TX",
"view_raw_tx_data": "View Raw Transaction Data",
"view_block": "View Block",
// block view
"block_title": "{1} Block Details",
"block_description": "Viewing block data from {1} block # {2}",
"block_previous": "Previous Block",
"block_next": "Next Block",
"block_genesis": "GENESIS",
"view_raw_block_data": "View Raw Block Data",
"view_tx": "View Transaction",
// error view
"error_title": "{1} Block Explorer Error",
"error_description": "The page you are looking for cannot be found",
"error_description_alt": "An error occurred which prevented the page from loading correctly",
"error_not_found": "Not Found",
// address view
"a_title": "{1} Wallet Address Details",
"a_description": "Viewing balance and transaction data from {1} address {2}",
"a_menu_showing": "Showing",
"a_menu_txs": "transactions",
"a_menu_all": "All",
"a_qr": "QR Code",
// masternode view
"mn_title": "{1} Masternodes",
"mn_description": "A listing of all masternodes known to be active on the {1} network",
"mn_masternode_list": "Masternode List",
// movement view
"move_title": "{1} Coin Movements",
"move_description": "A listing of larger movements where {1} or more {2} coins were sent in a single transaction",
// richlist view
"rl_title": "Top {1} Coin Holders",
"rl_description": "A listing of the richest {1} wallet addresses and breakdown of the current coin distribution",
"rl_received_coins": "Top 100 - Received Coins",
"rl_current_balance": "Top 100 - Current Balance",
"rl_received": "Received",
"rl_balance": "Balance",
"rl_wealth": "Wealth Distribution",
"rl_top25": "Top 1-25",
"rl_top50": "Top 26-50",
"rl_top75": "Top 51-75",
"rl_top100": "Top 76-100",
"rl_hundredplus": "101+",
// network view
"net_title": "{1} Network Peers",
"net_description": "A listing of {1} network peers that have connected to the explorer node in the last 24 hours",
"net_addnodes": "Add Nodes",
"net_connections": "Connections",
"net_address": "Address",
"net_protocol": "Protocol",
"net_subversion": "Sub-version",
"net_country": "Country",
// api view
"api_title": "{1} Public API",
"api_description": "A listing of public API endpoints for retrieving {1} coin data from the network without the need for a local wallet",
"api_documentation": "API Documentation",
"api_calls": "API Calls",
"api_getnetworkhashps": "Returns the current network hashrate. (hash/s)",
"api_getdifficulty": "Returns the current difficulty.",
"api_getconnectioncount": "Returns the number of connections the block explorer has to other nodes.",
"api_getmasternodelist": "Returns the complete list of masternodes on the network.",
"api_getmasternodecount": "Returns the total number of masternodes on the network.",
"api_getvotelist": "Returns the current vote list.",
"api_getblockcount": "Returns the number of blocks currently in the block chain.",
"api_getblockhash": "Returns the hash of the block at [index]; index 0 is the genesis block.",
"api_getblock": "Returns information about the block with the given hash.",
"api_getrawtransaction": "Returns raw transaction representation for given transaction id. decrypt can be set to 0(false) or 1(true).",
"api_getmaxmoney": 'Returns the maximum possible money supply.',
"api_getmaxvote": 'Returns the maximum allowed vote for the current phase of voting.',
"api_getvote": 'Returns the current block reward vote setting.',
"api_getphase": 'Returns the current voting phase (\'Mint\', \'Limit\' or \'Sustain\').',
"api_getreward": 'Returns the current block reward, which has been decided democratically in the previous round of block reward voting.',
"api_getsupply": 'Returns the current money supply.',
"api_getnextrewardestimate": 'Returns an estimate for the next block reward based on the current state of decentralized voting.',
"api_getnextrewardwhenstr": 'Returns a string describing how long until the votes are tallied and the next block reward is computed.',
// markets view
"mkt_title": "{1} Market Details",
"mkt_description": "Viewing {1} market data for the {2} exchange",
"mkt_hours": "24 hours",
"mkt_view_chart": "View 24 hour summary",
"mkt_view_summary": "View 24 hour chart",
"mkt_no_chart": "Chart data is not available via markets API",
"mkt_high": "High",
"mkt_low": "Low",
"mkt_volume": "Volume",
"mkt_top_bid": "Top Bid",
"mkt_top_ask": "Top Ask",
"mkt_last": "Last Price",
"mkt_yesterday": "Yesterday",
"mkt_change": "Change",
"mkt_sell_orders": "Sell Orders",
"mkt_buy_orders": "Buy Orders",
"mkt_price": "Price",
"mkt_amount": "Amount",
"mkt_total": "Total",
"mkt_trade_history": "Trade History",
"mkt_type": "Type",
"mkt_time_stamp": "Time Stamp",
"mkt_select": "Market Select",
"mkt_unexpected_api_data": "Received unexpected API data response",
// claim address view
"claim_title": "{1} Wallet Address Claim",
"claim_description": "Verify ownership of your {1} wallet address and set a custom display name in the explorer",
// orphans view
"orphan_title": "{1} Orphaned Blocks",
"orphan_description": "A listing of valid blocks that have been orphaned and do not belong to the main blockchain",
"orphan_block_list": "Orphaned Block List",
"orphan_block_hash": "Orphaned Block Hash",
"orphan_actual_block": "Actual Block",
"orphan_prev_block": "Previous Block",
"orphan_next_block": "Next Block",
"view_orphan": "View Orphaned Block",
// heavycoin rewards view
"heavy_title": "{1} Reward/Voting Details",
"heavy_description": "Viewing {1} voting data and coin reward change details",
"heavy_reward_voting_info": "Reward/voting information",
"heavy_vote": "Vote",
"heavy_cap": "Coin Cap",
"heavy_phase": "Phase",
"heavy_maxvote": "Max Vote",
"heavy_reward": "Reward",
"heavy_current": "Current Reward",
"heavy_estnext": "Est. Next",
"heavy_changein": "Reward change in approximately",
"heavy_key": "Key",
"heavy_lastxvotes": "Last 20 votes",
// sync
"script_launched": "Script launched with pid",
"stopping_sync_process": "Stopping sync process",
"finding_earliest_orphan": "Finding the earliest orphaned blockindex",
"calculating_market_price": "Calculating market price",
"syncing_blocks": "Syncing blocks",
"syncing_peers": "Syncing peers",
"syncing_masternodes": "Syncing masternodes",
"syncing_markets": "Syncing markets",
"checking_blocks": "Checking blocks",
"calculating_tx_count": "Calculating tx count",
"finding_last_blockindex": "Finding last blockindex",
"path_cannot_be_found": "'{1}' cannot be found",
// settings
"deprecated_setting": "Deprecated setting '{1}' has been mapped to the new location '{2}'. Be sure to make this change in settings.json as the old setting will be removed in a future release",
"unknown_setting": "Unknown setting '{1}' has been ignored",
"missing_setting": "Setting '{1}' is missing. Loading default value",
"continuing_using_defaults": "Continuing using defaults",
"missing_settings_file": "The {1} file is missing",
"error_processing_settings": "There was an error processing the {1} file",
// locale
"locale_lowercase_req": "Locale strings must start with a lowercase character",
"locale_unknown_string": "Unknown Locale String",
"locale_not_exists": "This setting doesn't exist or was removed"
};
exports.reloadLocale = function reloadLocale(locale) {
const fs = require('fs');
const jsonminify = require('jsonminify');
const localeFilename = './' + locale;
let localeStr;
try {
// read the settings sync
localeStr = fs.readFileSync(localeFilename).toString();
} catch(e) {
console.warn(`${exports.localization.missing_settings_file.replace('{1}', locale.split('/')[1])}. ${exports.localization.continuing_using_defaults}`);
}
var lsettings;
// try to parse the settings
try {
if (localeStr) {
localeStr = jsonminify(localeStr).replace(",]","]").replace(",}","}");
lsettings = JSON.parse(localeStr);
}
} catch(e) {
console.error(`${exports.localization.error_processing_settings.replace('{1}', locale.split('/')[1])}: ${e.message}`);
process.exit(1);
}
// loop through the settings
for (var i in lsettings) {
// test if the setting start with a low character
if (i.charAt(0).search("[a-z]") !== 0)
console.warn(`${lsettings.locale_lowercase_req}: '${i}'`);
if (exports.localization[i] !== undefined) {
// we know this setting, so we overwrite it
exports.localization[i] = lsettings[i];
} else {
// this setting is unknown. output a warning and discard it
console.warn(`${lsettings.locale_unknown_string}: '${i}'. ${lsettings.locale_not_exists}`);
}
}
return exports.localization;
};
+194
View File
@@ -0,0 +1,194 @@
const request = require('postman-request');
const base_url = 'https://dexomy.com/api/v2/';
const market_url_template = 'https://dexomy.com/exchange/dashboard?coin_pair={coin}_{base}';
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
function get_summary(coin, exchange, api_error_msg, cb) {
const req_url = base_url + 'get-pair-list/';
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (!body.success)
return cb((body.message != null ? body.message : api_error_msg), null, null);
else {
try {
// find the correct coin pair record
const pairObject = body.data.find(item => item.coin_pair_name === `${coin}/${exchange}`);
if (pairObject) {
const coindata = {
parent_coin_id: pairObject.parent_coin_id,
child_coin_id: pairObject.child_coin_id
};
const summary = {
'high': parseFloat(pairObject.high) || 0,
'low': parseFloat(pairObject.low) || 0,
'volume': parseFloat(pairObject.volume) || 0,
'last': parseFloat(pairObject.last_price) || 0,
'change': parseFloat(pairObject.price_change) || 0
};
return cb(null, summary, coindata);
} else
return cb(api_error_msg, null, null);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
});
}
function get_trades(parent_coin_id, child_coin_id, api_error_msg, cb) {
const req_url = `${base_url}get-exchange-market-trades?base_coin_id=${parent_coin_id}&trade_coin_id=${child_coin_id}`;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (!body.success)
return cb((body.message != null ? body.message : api_error_msg), null);
else {
try {
let trades = [];
for (let t = 0; t < body.data.transactions.data.length; t++) {
// convert the string timestamp to iso time and then to a unix timestamp
const isoTime = body.data.transactions.data[t].time.replace(' ', 'T') + 'Z';
const unixTimestamp = Math.floor(new Date(isoTime).getTime() / 1000);
trades.push({
ordertype: body.data.transactions.data[t].price_order_type.toString().toUpperCase(),
price: parseFloat(body.data.transactions.data[t].price) || 0,
quantity: parseFloat(body.data.transactions.data[t].amount) || 0,
timestamp: unixTimestamp
});
}
return cb(null, trades);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_orders(parent_coin_id, child_coin_id, api_error_msg, cb) {
const req_url = `${base_url}get-exchange-all-orders?base_coin_id=${parent_coin_id}&trade_coin_id=${child_coin_id}`;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (!body.success)
return cb((body.message != null ? body.message : api_error_msg), null, null);
else {
try {
let buys = [];
let sells = [];
for (let b = 0; b < body.data.buy_orders.data.length; b++) {
buys.push({
price: parseFloat(body.data.buy_orders.data[b].price) || 0,
quantity: parseFloat(body.data.buy_orders.data[b].amount) || 0
});
}
for (let s = 0; s < body.data.sell_orders.data.length; s++) {
sells.push({
price: parseFloat(body.data.sell_orders.data[s].price) || 0,
quantity: parseFloat(body.data.sell_orders.data[s].amount) || 0
});
}
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
});
});
}
function get_chartdata(parent_coin_id, child_coin_id, api_error_msg, cb) {
const end = Date.now();
const start = end - 86400000;
const req_url = `${base_url}get-exchange-chart-data?base_coin_id=${parent_coin_id}&trade_coin_id=${child_coin_id}&interval=15`;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function(error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object' || typeof body == 'string' || body instanceof String)
return cb(api_error_msg, null);
else if (!body.success)
return cb((body.message != null ? body.message : api_error_msg), null);
else {
try {
let chartdata = [];
for (let c = 0; c < body.data.length; c++) {
// only take values more recent than the last 24 hours
if ((body.data[c].time * 1000) > start)
chartdata.push([
parseInt(body.data[c].time * 1000),
parseFloat(body.data[c].open) || 0,
parseFloat(body.data[c].high) || 0,
parseFloat(body.data[c].low) || 0,
parseFloat(body.data[c].close) || 0
]);
}
return cb(null, chartdata);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
module.exports = {
market_name: 'Dexomy',
market_logo: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAACbVBMVEUAAAAoTTU2RzdBISEnAQQjIBkpGxolDg9bMi6sTD4nDhlTGyAVTy4QDwzl5uBbNjEUSCllcnIgJR0AFRcAEhYLNyK5KSA8KCgHPCU/TkkuJCUMHhy8q6eOlpUvNDMSMx1IVE1qXVJCWk8zRTGZeGSKk2/GnIFx0ZRQgl2Nonppl3geWy9WV1aOeXusSz4iOyFcOzMxRzI6KCWFiYmIMjKhMDCHeGuMZlYgAQM3OThXISe5pIC3wbVQZU5aOzNlZFdigH9sbGegMixKBAjEYlBBDQ1ZaE0dNiynSzhXGB5EFBaMkZJhX2EcERVkMDGhb2sdExgoQCJKJh9sGxtgPz+OEhM0Py2jamYKExNiNyo2AAdABwJjKiVZWVeOTj8bXzm4Tjk3STd3Oi0mKi0KOiosJScrMSQ3KiN2JyMANiJZHB9NKhobFBWOEBRqCxRVDxMKDxN9BhMBCgpKAAUuAAKrxY6DsXpkc3aAqnOTdHN/unHcgXBla255mWtjZmFLa19SjFokhFmPlFTCWVLNcU5HTEhHRUaNYENveUKTZEIjSUKfaEGQZkC4Uz01YjtkdzokZzo9YzpXOzrpSzk7VDg3NDjJPze0SjZMPjVvODJvSDEVPjFVNTGUNjBNMjCGNy+2Ly8pPi3XMS1RKi1eSiykSytAPisfMCvZJykkQCh+NCg+OCU4RSRKMSQ6MyMeICJYMCGsHiE5FyEAKB9AJh9SJB9dQh0AOx2gLB0vLB0PJR0zHR0hHRx8GhuJEBtuDxsCFhhsHReiDxefGxYgDhROABQALhMCIBMoFxIrGRBTBg0tBg13AAumAAZhAADJFxIcAAAAXXRSTlMA/hMI1UAcD/z6+vf29PLy8vHx8fHw8O/v7e3t7Onp5uXf3tzVzMrJx8XFxcG/v7+9vby7u7m4trW0tKupqKelnpyclZCPjoyBfHp5dnNubGVXV1FORUA+PTAvJgb/bIgPAAABGklEQVQY0w3HQ2IDABAAwI1r27Zt23Zss7Zt27Zt803N3AaS1bxdbR1tHJz8fXyjsgEAU1ez1kTYO+vt3DkR89MASgpMqllfjEf+WMsgQ5AIgMLZrf5JN4nsq4Wlka4gHED+RT/l2znTkzj99IzQzIH05pWq7XdkYVFcI/OXW58CWfH2HTfGSfrosLLxn9NFFwDwu1xXQqtPsmY5PAHTAlAxlQ9UqoIiiUNmf9wtG0KCcvn+aGu4R0Bg6dvL/YQV6HlF0NvMsEhscIXkVkwOhegty+s5o+Jct9rzqY0jRB5A7JBIRBdSGgZ6hl9p1igApClvhjDf3k06lB0jMgAgBP+5yz0QSmUSWl+q/JF4VS0dbV0NAxVzd4z8/2atXThWWOQQAAAAAElFTkSuQmCC',
market_url_template: market_url_template,
market_url_case: 'u',
get_data: function(settings, cb) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, function(summary_error, stats, coindata) {
if (summary_error == null) {
get_orders(coindata.parent_coin_id, coindata.child_coin_id, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(coindata.parent_coin_id, coindata.child_coin_id, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_chartdata(coindata.parent_coin_id, coindata.child_coin_id, settings.api_error_msg, function (chart_error, chartdata) {
if (chart_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: chartdata});
else
return cb(chart_error, null);
});
} else
return cb(trade_error, null);
});
} else
return cb(order_error, null);
});
} else
return cb(summary_error, null);
});
}
};
+183
View File
@@ -0,0 +1,183 @@
const request = require('postman-request');
const base_url = 'https://api.dex-trade.com/v1/public/';
const base_chart_url = 'https://socket.dex-trade.com/graph/';
const market_url_template = 'https://dex-trade.com/spot/trading/{coin}{base}';
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
function get_summary(coin, exchange, api_error_msg, bid, ask, cb) {
const req_url = base_url + 'ticker?pair=' + coin + exchange;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.status == null || body.status == false)
return cb((body.error != null ? body.error : api_error_msg), null);
else {
try {
const summary = {
'high': parseFloat(body.data.high) || 0,
'low': parseFloat(body.data.low) || 0,
'volume': parseFloat(body.data.volume_24H) || 0,
'bid': parseFloat(bid) || 0,
'ask': parseFloat(ask) || 0,
'last': parseFloat(body.data.last) || 0
};
return cb(null, summary);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_trades(coin, exchange, api_error_msg, cb) {
const req_url = base_url + 'trades?pair=' + coin + exchange;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.status == null || body.status == false)
return cb((body.error != null ? body.error : api_error_msg), null);
else {
try {
let trades = [];
for (let t = 0; t < body.data.length; t++) {
trades.push({
ordertype: body.data[t].type,
price: parseFloat(body.data[t].rate) || 0,
quantity: parseFloat(body.data[t].volume) || 0,
timestamp: parseInt(body.data[t].timestamp)
});
}
return cb(null, trades);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_orders(coin, exchange, api_error_msg, cb) {
const req_url = base_url + 'book?pair=' + coin + exchange;
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (body.status == null || body.status == false)
return cb((body.error != null ? body.error : api_error_msg), null, null);
else {
try {
let buys = [];
let sells = [];
for (let b = 0; b < body.data.buy.length; b++) {
buys.push({
price: parseFloat(body.data.buy[b].rate) || 0,
quantity: parseFloat(body.data.buy[b].volume) || 0
});
}
for (let s = 0; s < body.data.sell.length; s++) {
sells.push({
price: parseFloat(body.data.sell[s].rate) || 0,
quantity: parseFloat(body.data.sell[s].volume) || 0
});
}
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
});
}
function get_chartdata(coin, exchange, api_error_msg, cb) {
const end = Date.now();
const start = end - 86400000;
const req_url = base_chart_url + 'hist?t=' + coin + exchange + '&r=15&limit=100';
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object' || typeof body == 'string' || body instanceof String)
return cb(api_error_msg, null);
else {
try {
let chartdata = [];
for (let c = 0; c < body.length; c++) {
// only take values more recent than the last 24 hours
if ((body[c].time * 1000) > start)
chartdata.push([
parseInt(body[c].time * 1000),
parseFloat(body[c].open) || 0,
parseFloat(body[c].high) || 0,
parseFloat(body[c].low) || 0,
parseFloat(body[c].close) || 0
]);
}
return cb(null, chartdata);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
module.exports = {
market_name: 'Dex-Trade',
market_logo: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGTGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNi4wLWMwMDIgNzkuMTY0NDYwLCAyMDIwLzA1LzEyLTE2OjA0OjE3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMiAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIyLTA2LTI2VDIxOjEwOjEwLTA2OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDIyLTA2LTI2VDIxOjEwOjEwLTA2OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMi0wNi0yNlQyMToxMDoxMC0wNjowMCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozNDk5ZmMyYy02YjE0LWNhNDItOWNkYS05ODI4YTQ5MTBiNWMiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDpjMzIwOGQ5Yy05M2MyLTNkNDEtYTI0OC0yMjhkMjJkNjhmMmEiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDoxYmVhYmUxYS1hY2FlLTQ1NGEtYThjMy1mMjlkMWNjOTBhZjkiIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoxYmVhYmUxYS1hY2FlLTQ1NGEtYThjMy1mMjlkMWNjOTBhZjkiIHN0RXZ0OndoZW49IjIwMjItMDYtMjZUMjE6MTA6MTAtMDY6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4yIChXaW5kb3dzKSIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6MzQ5OWZjMmMtNmIxNC1jYTQyLTljZGEtOTgyOGE0OTEwYjVjIiBzdEV2dDp3aGVuPSIyMDIyLTA2LTI2VDIxOjEwOjEwLTA2OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgMjEuMiAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDxwaG90b3Nob3A6RG9jdW1lbnRBbmNlc3RvcnM+IDxyZGY6QmFnPiA8cmRmOmxpPjMyOTEwNDQzQzdFMjhCQTc2QTlCNTRFQkNFMjczMDkwPC9yZGY6bGk+IDwvcmRmOkJhZz4gPC9waG90b3Nob3A6RG9jdW1lbnRBbmNlc3RvcnM+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+3wqdeQAAA4xJREFUOI1NU2tMG1QUPrzpBlRs0U4efTAcK6UMQcu2zsdiZkZndKMjCyoUSCbskel8xB9zw2abmEDiwEQIREVd3TRubqL82SYT1gkUSmlpxyhtN1oeIzCpFST8+Ly96uJNvuSec/J955x7zqVx9x2a8EzSQL+Vhqw2amn7XLVHX96oVGlsaVJlUJKaFVRv0jpe2l3WZKw7XXjlSi/dHBimEecdGhrxEN0e91Hwj2Vyu31kqK41iiWZIEpgIFz9pRsXLlzm9zDWJKxD2StVjdYRJ03PLZFleILI5wvQ/MIilejLu4jiERUvRnyiBIaqWvx3tmp34HsmdLzuFBd6QVfS4/PPkcs9RTQzt0BHjr5nJIrGWmEqFI/n4zVDDTwe7wOBu34/Fu7fx++Li6DIRCYSAUN1zae+ST/RxUtdiqSH0yEUy1hQiJOnGljZlzixu/sGNm/RYnb2Hvr6+3BvbhbllbVMIAoxAhG+MX1bSIaqg00UIeTOQ0fehWPUha/PmtDS2obo+BResiq3COabfQgEAvjhcifzrQVFJGJvacV5Ktr6vJsoEhtVGsywTMM2G/YfeIMTk1PkWJ/9JH/UvCe0aGg4A7P5N+zeW8F8Aqjzt/hJ/KhiRbJOynsMBoP4sfNnaJ8tRlyCBPKsPEgz1UhX5CKW2U3NLTh3/jscOPwWkkUZSJfn/MUSJa7WHHqH92yxWNB9vYdNIgVpshxODiNNpgJFPQS7YxST/gB27ipBZnYBHnlswwrlFWi9QqYmX78JoVAInT918fIj40ScLM/KR6pMyX11H3zIE7V/9iW3c9Sbp6miuqYlbJTuq+TBcBums+dQrNNDkCTh/QtFMjyl2YZr164/GG1axgZoirZfpK86TMrY2CQ4nE78/9jtdpQb9kO3aw+am1vhdI3B4/PC6/Xh1q3bKC2rxPETp7fR0vIyvfn2+x/LMnOhe1GPg4ePwniyHq2t7VxkaelPhhACU/+MUCiS8vJfNbxuWlldZavsnyLvZICU6qLecCAiJhmFRdv5Kh87ZkRbeweustK9vrtsmQY4OTunwOp2eykwPUvUZxmhwMw8ucYnqLTM8EnsGjFfKqK4fz+VgCGGE6MFKXhZv69jcMgWOb8QIuuwk2jI5iSbY4wGbaP0a6+Z6usbnynWlXzBlmRMqlAHMxS5wY25GvfTz+00nTB+tKPHfIP6+gfJ5ZogO+P9DaehK5oI+uoTAAAAAElFTkSuQmCC',
market_url_template: market_url_template,
market_url_case: 'u',
get_data: function(settings, cb) {
// ensure coin info is uppercase
settings.coin = settings.coin.toUpperCase();
settings.exchange = settings.exchange.toUpperCase();
get_orders(settings.coin, settings.exchange, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(settings.coin, settings.exchange, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, (buys == null || buys.length == 0 ? null : buys[0].price), (sells == null || sells.length == 0 ? null : sells[0].price), function(summary_error, stats) {
if (summary_error == null) {
get_chartdata(settings.coin, settings.exchange, settings.api_error_msg, function (chart_error, chartdata) {
if (chart_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: chartdata});
else
return cb(chart_error, null);
});
} else
return cb(summary_error, null);
});
} else
return cb(trade_error, null);
});
} else
return cb(order_error, null);
});
}
};
+166
View File
@@ -0,0 +1,166 @@
const request = require('postman-request');
const base_url = 'https://api.freiexchange.com/public/';
const market_url_template = '{url_prefix}/market/{coin}/{base}';
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
function get_summary(coin, exchange, api_error_msg, cb) {
const req_url = base_url + 'ticker/' + coin;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object') {
const summary = {
'high': 0,
'low': 0,
'volume': 0,
'volume_btc': 0,
'bid': 0,
'ask': 0,
'last': 0,
'change': 0
};
return cb(null, summary);
} else if (body.success != null && body.success == false)
return cb((body.result != null && body.result.message != null ? body.result.message : api_error_msg), null);
else {
try {
const prefix = body[coin + '_' + exchange];
const summary = {
'high': parseFloat(prefix[0].high) || 0,
'low': parseFloat(prefix[0].low) || 0,
'volume': parseFloat(prefix[0].volume24h) || 0,
'volume_btc': parseFloat(prefix[0][`volume24h_${exchange.toLowerCase()}`]) || 0,
'bid': parseFloat(prefix[0].highestBuy) || 0,
'ask': parseFloat(prefix[0].lowestSell) || 0,
'last': parseFloat(prefix[0].last) || 0,
'change': parseFloat(prefix[0].percent_change_24h) || 0
};
return cb(null, summary);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_trades(coin, exchange, api_error_msg, cb) {
// NOTE: Commenting out the trade data since the trades api seems to have been discontinued.
// It will be reimplemented again later if the trades api ever returns.
// const req_url = base_url + 'trades/' + coin + (exchange == 'LTC' ? '/LTC' : '');
// // pause for 2 seconds before continuing
// rateLimit.schedule(function() {
// request({uri: req_url, json: true}, function (error, response, body) {
// if (error)
// return cb(error, null);
// else if (body == null || body == '' || typeof body !== 'object')
// return cb(api_error_msg, null);
// else if (body.success != null && body.success == false)
// return cb((body.result != null && body.result.message != null ? body.result.message : api_error_msg), null);
// else {
// try {
// let trades = [];
// for (let t = 0; t < body.length; t++) {
// trades.push({
// ordertype: body[t].type,
// price: parseFloat(body[t].price) || 0,
// quantity: parseFloat(body[t].total_coin) || 0,
// timestamp: parseInt(new Date(body[t].time.toString().replace(' ', 'T') + 'Z').getTime() / 1000)
// });
// }
// return cb(null, trades);
// } catch(err) {
// return cb(api_error_msg, null);
// }
// }
// });
// });
return cb(null, []);
}
function get_orders(coin, exchange, api_error_msg, cb) {
const req_url = base_url + 'orderbook/' + coin + (exchange == 'LTC' ? '/LTC' : '');
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (body.success != null && body.success == false)
return cb((body.result != null && body.result.message != null ? body.result.message : api_error_msg), null, null);
else {
try {
let buys = [];
let sells = [];
for (let b = 0; b < body.BUY.length; b++) {
buys.push({
price: parseFloat(body.BUY[b].price) || 0,
quantity: parseFloat(body.BUY[b].amount) || 0
});
}
for (let s = 0; s < body.SELL.length; s++) {
sells.push({
price: parseFloat(body.SELL[s].price) || 0,
quantity: parseFloat(body.SELL[s].amount) || 0
});
}
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
});
}
module.exports = {
market_name: 'FreiExchange',
market_name_alt: 'FreiXLite',
market_logo: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF8WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNi4wLWMwMDIgNzkuMTY0NDYwLCAyMDIwLzA1LzEyLTE2OjA0OjE3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMiAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIyLTA2LTI2VDE2OjU2OjA2LTA2OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDIyLTA2LTI2VDE2OjU2OjA2LTA2OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMi0wNi0yNlQxNjo1NjowNi0wNjowMCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpjM2IyNDVkYy1kZDI2LWYwNGEtYmIwYS03OWJjNDhmZTQxMzMiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDozZWIzNDAxZC00N2U4LTFmNGUtOGYwMi1kZmMzODg0MzFlZWYiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo3NzY1YTNlYi1mMjRlLWVlNGQtOGM0My0xYTY3NjgzYTNkMTAiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjc3NjVhM2ViLWYyNGUtZWU0ZC04YzQzLTFhNjc2ODNhM2QxMCIgc3RFdnQ6d2hlbj0iMjAyMi0wNi0yNlQxNjo1NjowNi0wNjowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIxLjIgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDpjM2IyNDVkYy1kZDI2LWYwNGEtYmIwYS03OWJjNDhmZTQxMzMiIHN0RXZ0OndoZW49IjIwMjItMDYtMjZUMTY6NTY6MDYtMDY6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4yIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz48i0LMAAAC2UlEQVQ4jV1T70tTURh+7z0/7tbcKjT7XdC3QIi0yBD6F/rQl8A+SIUlaISETSVGn6QocFaYWhARTpG0MLAvFQZFEbg+ZVAYVnO7cwuderubc2/vOS2VLjzsfe/O87zPOee5ABwABMAOwcBrGFBjikA7k7UhJm/3c+vhVc7vdjDZcIKJvfsYB9Og9XwDcbYTylXzV8AigSCTzZ+FjOelhSg9iELo3xXqvwmRvcNFWBqGALZegCkY0MPlMHKJK4zjLMEmJLhAW0icJbhUI+E159EtvKQcxE4AuQ30c5NbvYqcAsAZQnwdbMPUIromoJQ4Jj3vwfSBxhGTHUOT4YLXh/PhTsw+G0X3+RhmX77Apf5+jHu8GCNiJhzG+UgEberRNLDJMK/o6UNcDKOaFghg3nXw/8eurCRU6ToZDGJGuSD0ADzSAtNC2r+UPX8AsVBAJxrFaerVVHd8HJ2JKLqZDC6MjGCS3iXBcBp8/ub2+vrGo9XVFZDilhMvCuRTKczGZ3D+chDnzp/DdLBVT87ZNsZMU08m312N9+6fKhrMQkpYTqIosDz5adX6MsGJx3S9MPpUO1ICIYBbTX19tcVlDkzJtS0UXBezX7/gD58P0y1BXFHkkWHM5XJoVxzQt5Rk/Hejr+RSy+kzDYeqqvbDIJeP9SH6N2pJ9+MEft+0GfNUZwYG9HkU1Kg3b/En1YuUD7W+GyCiD/GwyWqQ9qeucXEwgnO073RdHbp0jTYJKetzoRBt4wnGGMMU5UJl4QLjrRQEJWHCNS56VWzT/8JDuUgUg5OkGCeK75MUKEUe5d53AF4KMAUJDEkaArqFHEJlj+I6qyKs4kwEhST1WfUfkV8J9qEUfGUAW4lcphyQAJfgFRYEubg4KWRsWU+yivCg6qeEWOri1g2hvx6LeOpDKl0T2EMCfsbgIOMlbcxzso2Jzg4mHrQzfuc6k2ePc7FrNzll+uQ8qwJ/AJ4ryGtYbOHVAAAAAElFTkSuQmCC',
market_logo_alt: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF8WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNi4wLWMwMDIgNzkuMTY0NDYwLCAyMDIwLzA1LzEyLTE2OjA0OjE3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMiAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIyLTA2LTI2VDE5OjE0OjMzLTA2OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDIyLTA2LTI2VDE5OjE0OjMzLTA2OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMi0wNi0yNlQxOToxNDozMy0wNjowMCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozYjE4MmI1ZC0zZjU3LWVhNGMtYWFiYS01NmQ0YjVkZWVmNTUiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDpiNWRkYTk5MS02MGNlLTc5NGQtOWFlNy04MDcwY2I3NWVjYzkiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDozMjM4NjRhMi0xNjk4LWU0NGUtODA5Yy1iYjc0ZjliM2UyMmEiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjMyMzg2NGEyLTE2OTgtZTQ0ZS04MDljLWJiNzRmOWIzZTIyYSIgc3RFdnQ6d2hlbj0iMjAyMi0wNi0yNlQxOToxNDozMy0wNjowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIxLjIgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDozYjE4MmI1ZC0zZjU3LWVhNGMtYWFiYS01NmQ0YjVkZWVmNTUiIHN0RXZ0OndoZW49IjIwMjItMDYtMjZUMTk6MTQ6MzMtMDY6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4yIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4U//lqAAACLUlEQVQ4y42TQUiTYRzGf4GXITsowi4WjIRFXnYLPNRRXSB6M8kCD2J2cAgeJJFEIwRDqA42QmjDTiW2lGkGkRRBGkSktYrUNDZnmOg+9ZvfvqfDNjEx8oWH9/I+//eB/+8hDISBD0AcWIH8GFzagDtJGNyAm+tQOQ98BwzgFTACRMiaR4AZ4DecT8FHgQ5qE8Z/wul14PX+AY+BR8Ay9B1mPKgtqJ4EhoExgHFgHq79z7hZVKSk0ymBZuDsMPAMYA6O5x7Zbrfk9WbkdivtcEgDA9pubdWVzk6F6uslUApib+DYHEACAgJZeXmyUinlTjqRkBmJSJLiNTW63NWl5xUVe4liUHm/pARMWBLI9nhkS9rt79euzyfLspSWJL9fUVBDMKjPpaUSaA2in9rbb/dGImcQmALJ55MkWZK2q6tlR6Oyk0kJ9MLr1dVAIPf7zpfu7oe5pAh2BFJzcyZBU5PMlhZJkm0YEuhBebkuDg0p0NioREGBtVpWNpE0jIW4NIUJywIpGFRa0o7LJUkyp6eVlmT39mrU49GttjZd7+nRUnGxBOlFh6Mr3NEBcbgnkGZnZS0syKqtlR0KyXI6pbo62VVVh671K1yYIoPwCYHkckmFhToKTCbE3gHvASaBH9B+FGNOb+HcHkhPslwn4MZRzAZUjWfxf0qW5zDwDdiCSvMfZTJgYgVO/QJe7u/CGDAKLAIbmftkAvwW3N2FQRP6VqFhEfKXM439a8AfCVrpWXEdq70AAAAASUVORK5CYII=',
market_url_template: market_url_template,
market_url_case: 'u',
market_url: function(settings) {
return 'https://' + (settings.exchange.toUpperCase() == 'LTC' ? 'freixlite' : 'freiexchange') + '.com';
},
isAlt: function(settings) {
return settings.exchange.toUpperCase() == 'LTC';
},
get_data: function(settings, cb) {
// ensure coin info is uppercase
settings.coin = settings.coin.toUpperCase();
settings.exchange = settings.exchange.toUpperCase();
get_orders(settings.coin, settings.exchange, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(settings.coin, settings.exchange, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, function(summary_error, stats) {
if (summary_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: null});
else
return cb(summary_error, null);
});
} else
return cb(trade_error, null);
});
} else
return cb(order_error, null);
});
}
};
+139
View File
@@ -0,0 +1,139 @@
const request = require('postman-request');
const base_url = 'https://trade.nestex.one/api/';
const market_url_template = 'https://trade.nestex.one/spot/{coin}';
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
function get_summary(coin, exchange, api_error_msg, cb) {
const req_url = base_url + 'cg/tickers/' + coin + '_' + exchange;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.error != null)
return cb(body.error, null);
else {
try {
const summary = {
'high': parseFloat(body.high) || 0,
'low': parseFloat(body.low) || 0,
'volume': parseFloat(body.base_volume) || 0,
'volume_btc': parseFloat(body.target_volume) || 0,
'bid': parseFloat(body.bid) || 0,
'ask': parseFloat(body.ask) || 0,
'last': parseFloat(body.last_price) || 0
};
return cb(null, summary);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_trades(coin, exchange, api_error_msg, cb) {
const req_url = base_url + 'cg/tradebook/' + coin + '_' + exchange;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.error != null)
return cb(body.error, null);
else {
try {
let trades = [];
for (let t = 0; t < body.data.length; t++) {
trades.push({
ordertype: body.data[t].side.toString().toUpperCase(),
price: parseFloat(body.data[t].price) || 0,
quantity: parseFloat(body.data[t].quantity) || 0,
timestamp: parseInt(body.data[t].timestamp) / 1000
});
}
return cb(null, trades);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_orders(coin, exchange, api_error_msg, cb) {
const req_url = base_url + 'cg/orderbook/' + coin + '_' + exchange + '?depth=100';
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (body.error != null)
return cb(body.error, null, null);
else {
try {
let buys = [];
let sells = [];
const bids = Object.entries(body.bids);
const asks = Object.entries(body.asks);
for (let b = 0; b < bids.length; b++) {
buys.push({
price: parseFloat(bids[b][0]) || 0,
quantity: parseFloat(bids[b][1]) || 0
});
}
for (let a = 0; a < asks.length; a++) {
sells.push({
price: parseFloat(asks[a][0]) || 0,
quantity: parseFloat(asks[a][1]) || 0
});
}
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
});
}
module.exports = {
market_name: 'NestEx',
market_logo: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAe1BMVEUAAAD/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQX/yQVH+eRqAAAAKXRSTlMArGRHvXthTriLf3FsaFVBMhIGpZqRd1o5JBfRysiyj4RdKSDv4NiehahrJacAAACTSURBVBjTdc1XDsIwEEXRce92nN4rbf8rRApRAAnO37vzMfBHq9T2FfQs0efGFmxu3jvFIYtuSM+Q3HRUYXHHuQHHACXrhb+CQJDMul1MRQCXAdIoCHS8tXGCGosSCoSQIVg+TIUzeicAnubSs2ZjfsyR238UtRC0r0itCOw4kpSxkWYWDqHX3bUcPJwaPhV8hZ+exboH2W57FV0AAAAASUVORK5CYII=',
market_url_template: market_url_template,
market_url_case: 'u',
get_data: function(settings, cb) {
get_orders(settings.coin, settings.exchange, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(settings.coin, settings.exchange, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, function(summary_error, stats) {
if (summary_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: null});
else
return cb(summary_error, null);
});
} else
return cb(trade_error, null);
});
} else
return cb(order_error, null);
});
}
};
+181
View File
@@ -0,0 +1,181 @@
const request = require('postman-request');
const base_url = 'https://api.nonkyc.io/api/v2';
const market_url_template = 'https://nonkyc.io/market/{coin}_{base}';
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
function get_summary(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/market/getbysymbol/' + coin + '_' + exchange;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.error != null)
return cb((body.error.message != null ? body.error.message : api_error_msg), null);
else {
try {
const summary = {
'high': parseFloat(body.highPriceNumber) || 0,
'low': parseFloat(body.lowPriceNumber) || 0,
'volume': parseFloat(body.volumeNumber) || 0,
'volume_btc': parseFloat(body.volumeUsdNumber) || 0,
'bid': parseFloat(body.bestBidNumber) || 0,
'ask': parseFloat(body.bestAskNumber) || 0,
'last': parseFloat(body.lastPriceNumber) || 0,
'prev': parseFloat(body.yesterdayPriceNumber) || 0,
'change': parseFloat(body.changePercentNumber) || 0
};
return cb(null, summary);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_trades(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/historical_trades?ticker_id=' + coin + '_' + exchange + '&limit=300';
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.error != null)
return cb((body.error.message != null ? body.error.message : api_error_msg), null);
else {
try {
let trades = [];
for (let t = 0; t < body.length; t++) {
trades.push({
ordertype: body[t].type,
price: parseFloat(body[t].price) || 0,
quantity: parseFloat(body[t].base_volume) || 0,
timestamp: parseInt(new Date(body[t].trade_timestamp).getTime() / 1000)
});
}
return cb(null, trades);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_orders(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/market/getorderbookbysymbol/' + coin + '_' + exchange;
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (body.error != null)
return cb((body.error.message != null ? body.error.message : api_error_msg), null, null);
else {
try {
let buys = [];
let sells = [];
for (let b = 0; b < body.bids.length; b++) {
buys.push({
price: parseFloat(body.bids[b].numberprice) || 0,
quantity: parseFloat(body.bids[b].quantity) || 0
});
}
for (let s = 0; s < body.asks.length; s++) {
sells.push({
price: parseFloat(body.asks[s].numberprice) || 0,
quantity: parseFloat(body.asks[s].quantity) || 0
});
}
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
});
}
function get_chartdata(coin, exchange, api_error_msg, cb) {
const end = Date.now() / 1000;
const start = end - 86400;
const req_url = base_url + '/market/candles/?symbol=' + coin + '_' + exchange + '&from=' + parseInt(start).toString() + '&to=' + parseInt(end).toString() + '&resolution=15' ;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object' || typeof body == 'string' || body instanceof String)
return cb(api_error_msg, null);
else if (body.error != null)
return cb((body.error.message != null ? body.error.message : api_error_msg), null);
else {
try {
let chartdata = [];
for (let c = 0; c < body.bars.length; c++) {
chartdata.push([
parseInt(body.bars[c].time),
parseFloat(body.bars[c].open) || 0,
parseFloat(body.bars[c].high) || 0,
parseFloat(body.bars[c].low) || 0,
parseFloat(body.bars[c].close) || 0
]);
}
return cb(null, chartdata);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
module.exports = {
market_name: 'Nonkyc',
market_logo: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAKrmlDQ1BJQ0MgUHJvZmlsZQAASImVlwdUE1kXgN/MpBdaQihSQm/SWwApIbTQpYONkAQIJcZAQLEjiyu4FlREUFF0VUTBtQBiRxTbotiwb5BFRFkXC6Ki8g9wCLv7n///z3/Peed+c+e+e+97M2/OHQCoKjyJJAtWASBbnCuNCvRlJiQmMfF9AAFaAABdQOTxcyTsyMhQ9ApM6r/Lx/sAGtN3rMdi/fv9/yqqAmEOHwAoEuUUQQ4/G+Xj6HjFl0hzAUB2oXaj/FzJGLehTJeiBaL8YIzTJnhgjFPGGQPGfWKiOCjTASBQeDxpGgAUJmpn5vHT0DgUH5TtxAKRGGUJyl7Z2fMFKB9B2Rz1QW2UsfislL/ESftbzBRFTB4vTcETaxkXgp8oR5LFW/R/bsf/luws2WQOU3RQ0qVBUWP50D17kDk/RMHilPCISRYJJmoa43RZUOwk83M4SZMs4PmFKOZmhYdOcqoogKuIk8uNmWRhjn/0JEvnRylypUo57EnmScfzklCWyzJjFfZ0IVcRvyA9Jn6S80Rx4ZOckxkdMuXDUdilsihF/UJxoO9U3gDF2rNz/rJeEVcxNzc9Jkixdt5U/UIxeypmToKiNoHQz3/KJ1bhL8n1VeSSZEUq/IVZgQp7Tl60Ym4u+kJOzY1U7GEGLzhykoEIhAEe4DOVJwmAXOHC3LGFcOZLFklFaem5TDZ6woRMrphvM53pYOfgCMDYeZ14Hd4zxs8hxLg2ZVu1EwDP46Ojo6embCEtABwrRR9L15TNbCkAShcAuFLFl0nzJmzjZwmLPj1lQEe/BnrACJgDa+AAXIAH8AH+IBhEgBiQCOaitaaDbCAF+WAJWAmKQSnYALaASlAN9oAD4DA4CprAaXABXAbXwS1wDzwGctALXoNB8BGMQBCEh6gQDdKC9CETyApygFiQF+QPhUJRUCKUDKVBYkgGLYFWQaVQGVQJ7YZqoV+gk9AF6CrUCT2EuqF+6B30BUZgCkyHdWFT2BZmwWw4BI6B58Bp8AK4AC6C18EVcA18CG6EL8DX4XuwHH4NDyEAISMMxACxRlgIB4lAkpBURIosQ0qQcqQGqUdakHbkDiJHBpDPGByGhmFirDEemCBMLIaPWYBZhlmLqcQcwDRi2jB3MN2YQcx3LBWrg7XCumO52ARsGjYfW4wtx+7DnsBewt7D9mI/4nA4Bs4M54oLwiXiMnCLcWtxO3ANuPO4TlwPbgiPx2vhrfCe+Ag8D5+LL8Zvwx/Cn8PfxvfiPxHIBH2CAyGAkEQQEwoJ5YSDhLOE24Q+wghRhWhCdCdGEAXERcT1xL3EFuJNYi9xhKRKMiN5kmJIGaSVpApSPekS6QnpPZlMNiS7kWeSReQV5AryEfIVcjf5M0WNYknhUGZTZJR1lP2U85SHlPdUKtWU6kNNouZS11FrqRepz6iflGhKNkpcJYHScqUqpUal20pvlInKJsps5bnKBcrlyseUbyoPqBBVTFU4KjyVZSpVKidVulSGVGmq9qoRqtmqa1UPql5VfamGVzNV81cTqBWp7VG7qNZDQ2hGNA6NT1tF20u7ROul4+hmdC49g15KP0zvoA+qq6k7qcepL1SvUj+jLmcgDFMGl5HFWM84yrjP+KKhq8HWEGqs0ajXuK0xrDlN00dTqFmi2aB5T/OLFlPLXytTa6NWk9ZTbYy2pfZM7XztndqXtAem0ad5TONPK5l2dNojHVjHUidKZ7HOHp0bOkO6erqBuhLdbboXdQf0GHo+ehl6m/XO6vXr0/S99EX6m/XP6b9iqjPZzCxmBbONOWigYxBkIDPYbdBhMGJoZhhrWGjYYPjUiGTEMko12mzUajRorG8cZrzEuM74kQnRhGWSbrLVpN1k2NTMNN50tWmT6UszTTOuWYFZndkTc6q5t/kC8xrzuxY4C5ZFpsUOi1uWsKWzZbplleVNK9jKxUpktcOqczp2utt08fSa6V3WFGu2dZ51nXW3DcMm1KbQpsnmja2xbZLtRtt22+92znZZdnvtHtur2QfbF9q32L9zsHTgO1Q53HWkOgY4LndsdnzrZOUkdNrp9MCZ5hzmvNq51fmbi6uL1KXepd/V2DXZdbtrF4vOimStZV1xw7r5ui13O+322d3FPdf9qPufHtYemR4HPV7OMJshnLF3Ro+noSfPc7en3Ivpley1y0vubeDN867xfu5j5CPw2efTx7ZgZ7APsd/42vlKfU/4DnPcOUs55/0Qv0C/Er8OfzX/WP9K/2cBhgFpAXUBg4HOgYsDzwdhg0KCNgZ1cXW5fG4tdzDYNXhpcFsIJSQ6pDLkeahlqDS0JQwOCw7bFPYk3CRcHN4UASK4EZsinkaaRS6IPDUTNzNyZtXMF1H2UUui2qNp0fOiD0Z/jPGNWR/zONY8VhbbGqccNzuuNm443i++LF6eYJuwNOF6onaiKLE5CZ8Ul7QvaWiW/6wts3pnO88unn1/jtmchXOuztWemzX3zDzlebx5x5KxyfHJB5O/8iJ4NbyhFG7K9pRBPoe/lf9a4CPYLOgXegrLhH2pnqllqS/TPNM2pfWne6eXpw+IOKJK0duMoIzqjOHMiMz9maNZ8VkN2YTs5OyTYjVxprhtvt78hfM7JVaSYol8gfuCLQsGpSHSfTlQzpyc5lw62hjdkJnLfpB153nlVeV9yo/LP7ZQdaF44Y1FlovWLOorCCj4eTFmMX9x6xKDJSuXdC9lL929DFqWsqx1udHyouW9KwJXHFhJWpm58tdCu8Kywg+r4le1FOkWrSjq+SHwh7pipWJpcddqj9XVP2J+FP3YscZxzbY130sEJddK7UrLS7+u5a+99pP9TxU/ja5LXdex3mX9zg24DeIN9zd6bzxQplpWUNazKWxT42bm5pLNH7bM23K13Km8eitpq2yrvCK0onmb8bYN275Wplfeq/Ktatius33N9uEdgh23d/rsrK/WrS6t/rJLtOvB7sDdjTWmNeV7cHvy9rzYG7e3/WfWz7X7tPeV7vu2X7xffiDqQFuta23tQZ2D6+vgOlld/6HZh24d9jvcXG9dv7uB0VB6BByRHXn1S/Iv94+GHG09xjpWf9zk+PYTtBMljVDjosbBpvQmeXNic+fJ4JOtLR4tJ07ZnNp/2uB01Rn1M+vPks4WnR09V3Bu6Lzk/MCFtAs9rfNaH19MuHi3bWZbx6WQS1cuB1y+2M5uP3fF88rpq+5XT15jXWu67nK98YbzjRO/Ov96osOlo/Gm683mW263WjpndJ697X37wh2/O5fvcu9evxd+r/N+7P0HXbO75A8ED14+zHr49lHeo5HHK55gn5Q8VXla/kznWc1vFr81yF3kZ7r9um88j37+uIff8/r3nN+/9ha9oL4o79Pvq33p8PJ0f0D/rVezXvW+lrweGSj+Q/WP7W/M3xz/0+fPG4MJg71vpW9H3619r/V+/wenD61DkUPPPmZ/HBku+aT16cBn1uf2L/Ff+kbyv+K/Vnyz+NbyPeT7k9Hs0VEJT8obbwUQdMCpqQC82w8ANREA2i20f5g10U+PCzTxDzBO4D/xRM89Li4A1KNqrC3inAfgCDpMfdDYqB5riWJ8AOzoqBiTve94nz4mOPSPpR6vnF9L7myxXQH+IRM9/F/q/qcGY1GdwD/1vwDFOAe+Dmu0xAAAAJZlWElmTU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAACQAAAAAQAAAJAAAAABAAOShgAHAAAAEgAAAISgAgAEAAAAAQAAABCgAwAEAAAAAQAAABAAAAAAQVNDSUkAAABTY3JlZW5zaG90JdHC9QAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAtdpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj4KICAgICAgICAgPGV4aWY6UGl4ZWxYRGltZW5zaW9uPjE5ODwvZXhpZjpQaXhlbFhEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOlVzZXJDb21tZW50PlNjcmVlbnNob3Q8L2V4aWY6VXNlckNvbW1lbnQ+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj4xOTg8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICAgICA8dGlmZjpSZXNvbHV0aW9uVW5pdD4yPC90aWZmOlJlc29sdXRpb25Vbml0PgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj4xNDQ8L3RpZmY6WVJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOlhSZXNvbHV0aW9uPjE0NDwvdGlmZjpYUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+Cjo54jUAAAIhSURBVDgRjVPPaxNBFJ6Zna2JiJBAEHuoWKht3YBI24s Line truncated
market_url_template: market_url_template,
market_url_case: 'u',
get_data: function(settings, cb) {
get_orders(settings.coin, settings.exchange, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(settings.coin, settings.exchange, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, function(summary_error, stats) {
if (summary_error == null) {
get_chartdata(settings.coin, settings.exchange, settings.api_error_msg, function (chart_error, chartdata) {
if (chart_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: chartdata});
else
return cb(chart_error, null);
});
} else
return cb(summary_error, null);
});
} else
return cb(trade_error, null);
});
} else
return cb(order_error, null);
});
}
};
+182
View File
@@ -0,0 +1,182 @@
const request = require('postman-request');
const base_url = 'https://api.poloniex.com/markets/';
const market_url_template = 'https://poloniex.com/trade/{coin}_{base}?type=spot';
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
function get_summary(coin, exchange, api_error_msg, cb) {
const req_url = base_url + coin + '_' + exchange + '/ticker24h';
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.message != null)
return cb(body.message, null);
else {
try {
const summary = {
'high': parseFloat(body.high) || 0,
'low': parseFloat(body.low) || 0,
'volume': parseFloat(body.quantity) || 0,
'volume_btc': parseFloat(body.amount) || 0,
'bid': parseFloat(body.bid) || 0,
'ask': parseFloat(body.ask) || 0,
'change': parseFloat(body.dailyChange || 0) * 100
};
return cb(null, summary);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_trades(coin, exchange, api_error_msg, cb) {
const req_url = base_url + coin + '_' + exchange + '/trades';
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.message != null)
return cb(body.message, null);
else {
try {
let trades = [];
for (let t = 0; t < body.length; t++) {
trades.push({
ordertype: body[t].takerSide,
price: parseFloat(body[t].price) || 0,
quantity: parseFloat(body[t].quantity) || 0,
timestamp: parseInt(new Date(body[t].ts).getTime() / 1000)
});
}
return cb(null, trades);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_orders(coin, exchange, api_error_msg, cb) {
const req_url = base_url + coin + '_' + exchange + '/orderBook?limit=50';
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (body.message != null)
return cb(body.message, null, null);
else {
try {
let buys = [];
let sells = [];
for (let b = 0; b < body.bids.length; b += 2) {
buys.push({
price: parseFloat(body.bids[b]) || 0,
quantity: parseFloat(body.bids[b + 1]) || 0
});
}
for (let s = 0; s < body.asks.length; s += 2) {
sells.push({
price: parseFloat(body.asks[s]) || 0,
quantity: parseFloat(body.asks[s + 1]) || 0
});
}
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
});
}
function get_chartdata(coin, exchange, api_error_msg, cb) {
const end = Date.now();
const start = end - 86400000;
const req_url = base_url + coin + '_' + exchange + '/candles?interval=MINUTE_15&limit=96&startTime=' + start.toString() + '&endTime=' + end.toString();
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object' || typeof body == 'string' || body instanceof String)
return cb(api_error_msg, null);
else if (body.message != null)
return cb(body.message, null);
else {
try {
let chartdata = [];
for (let c = 0; c < body.length; c++)
chartdata.push([
parseInt(body[c][9]),
parseFloat(body[c][2]) || 0,
parseFloat(body[c][1]) || 0,
parseFloat(body[c][0]) || 0,
parseFloat(body[c][3]) || 0
]);
return cb(null, chartdata);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
module.exports = {
market_name: 'Poloniex',
market_logo: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF8WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNi4wLWMwMDIgNzkuMTY0NDYwLCAyMDIwLzA1LzEyLTE2OjA0OjE3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMiAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIwLTEyLTI1VDIwOjU1OjMzLTA3OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDIwLTEyLTI1VDIwOjU1OjMzLTA3OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMC0xMi0yNVQyMDo1NTozMy0wNzowMCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDphMzU0YTQ5My02M2VlLTQ3NDUtOTAyMC1jZjQ5ZTZlODRlNDQiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDowZTZlOTkxZi05YTM4LTgxNDAtYTlmMS0yMGU3MThjOTU5YjMiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDplNzcwYmQ5Zi1kMzM2LTliNGQtYmVhMC0wOTIwNjZkNDIwZDIiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmU3NzBiZDlmLWQzMzYtOWI0ZC1iZWEwLTA5MjA2NmQ0MjBkMiIgc3RFdnQ6d2hlbj0iMjAyMC0xMi0yNVQyMDo1NTozMy0wNzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIxLjIgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDphMzU0YTQ5My02M2VlLTQ3NDUtOTAyMC1jZjQ5ZTZlODRlNDQiIHN0RXZ0OndoZW49IjIwMjAtMTItMjVUMjA6NTU6MzMtMDc6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4yIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4yAdy4AAACnUlEQVQ4y11TS09TQRid9raFloIY45/wHUNijEsXBjeKC40r3Wrig7b0AS229AVIotISATdiSohuVJDYEkXjxsSFCQlEDSASdvIwo4BiheOZK1x6bTLp3PnOOd/3nZlPOJKpOVs8IUWDXwqPT4p6rxTBkHSn0tKWSEqNq5J7EQgy5iGGcV+DVBw7ucIajRX33exAW6GA8PM8EoURnM/1QzQ2wZVMoZJLhBpxNpdDYmQE4Xwe7fw/QI6NXLGLGXY0hTH2eQalvzM9PbAEgrAFQ6jr7jbFxme+oCocgeIKF8uzU2B/uhW/VlYM0PzCAjR/AO5IM1alNM5//1zFoXQbLKzQmUxJobEXVSr7w6X+flOm7KvX2Hndg8WlJePs8sAAsV5UkWNV3pWxDJoFZ0tcD7wZHzeJnLvTiaPxhL4fm5qElYlcxNJAKK5wbApUsAUX+zrIwOL3H4bAV5Zf4fHB+/ARau9264a6iVUcx5YAFwSzVDMgvD5cuN9nquLdh48QV67CwgS2VHqLbBawlAhc7HtgEng7MQGNAlokAjsF7PH/BOz8cLe2wklnD7e149vyskH+ND+Psmv1SAwOoa73HkQgpLegbQnoJipDoi3QmH1scsqU/TiFT9y6re8nZ2dRRkx5LLZtInuXbnWNvC7/00ETOfD4CXaTgLU148w/NKRfeTVbsahrZDnSzgdzKtMFrK8bwPdT0xStRzkf2cRMySvd2MDpbBds5FSoGXFFY3IPK0BJ33/4ImtS9ISuq1WTTqO4srotQuxechRXWCPNxWOZLDpGRxEaHkacg3Kyp5dzEEI5y3TSMAvnoZZnsXwBgWfDaH/xEkc6M9CabxQFQXMi1vJvTL2b49zYJFV52uY466XyTB9nhVFYZlfcv+GHou2DaH9cAAAAAElFTkSuQmCC',
market_url_template: market_url_template,
market_url_case: 'u',
get_data: function(settings, cb) {
// ensure coin info is uppercase
settings.coin = settings.coin.toUpperCase();
settings.exchange = settings.exchange.toUpperCase();
get_orders(settings.coin, settings.exchange, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(settings.coin, settings.exchange, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, function(summary_error, stats) {
if (summary_error == null) {
get_chartdata(settings.coin, settings.exchange, settings.api_error_msg, function (chart_error, chartdata) {
if (chart_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: chartdata});
else
return cb(chart_error, null);
});
} else
return cb(summary_error, null);
});
} else
return cb(trade_error, null);
});
} else
return cb(order_error, null);
});
}
};
+144
View File
@@ -0,0 +1,144 @@
const request = require('postman-request');
const base_url = 'https://qutrade.io/api/v1/';
const market_url_template = 'https://qutrade.io/en/?market={coin}_{base}';
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
function get_summary(coin, exchange, api_error_msg, cb) {
const pair_key = coin.toLowerCase() + '_' + exchange.toLowerCase();
const req_url = base_url + 'market_data/?pair=' + pair_key;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object' || body.result == null || body.list == null || body.list[pair_key] == null)
return cb(api_error_msg, null);
else if (body.result !== 'success')
return cb(body.info || api_error_msg, null);
else {
try {
const pair_data = body.list[pair_key];
const summary = {
'high': parseFloat(pair_data.high) || 0,
'low': parseFloat(pair_data.low) || 0,
'volume': parseFloat(pair_data.asset_1_volume) || 0,
'volume_btc': parseFloat(pair_data.asset_2_volume) || 0,
'bid': parseFloat(pair_data.bid) || 0,
'ask': parseFloat(pair_data.ask) || 0,
'last': parseFloat(pair_data.price) || 0,
'change': parseFloat(pair_data.trend) || 0
};
return cb(null, summary);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_trades(coin, exchange, api_error_msg, cb) {
const pair_key = coin.toLowerCase() + '_' + exchange.toLowerCase();
const req_url = base_url + 'market_trades/?pair=' + pair_key + '&limit=100';
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object' || body.result == null || body.list == null || body.list.length == 0)
return cb(api_error_msg, null);
else if (body.result !== 'success')
return cb(body.info || api_error_msg, null);
else {
try {
let trades = [];
for (let t = 0; t < body.list.length; t++) {
trades.push({
ordertype: body.list[t].side.toString().toUpperCase(),
price: parseFloat(body.list[t].price) || 0,
quantity: parseFloat(body.list[t].amount) || 0,
timestamp: parseInt(body.list[t].timestamp)
});
}
return cb(null, trades);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_orders(coin, exchange, api_error_msg, cb) {
const pair_key = coin.toLowerCase() + '_' + exchange.toLowerCase();
const req_url = base_url + 'market_depth/?pair=' + pair_key + '&limit=100';
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object' || body.result == null || body.list == null || body.list[pair_key] == null)
return cb(api_error_msg, null, null);
else if (body.result !== 'success')
return cb(body.info || api_error_msg, null, null);
else {
try {
let buys = [];
let sells = [];
const pair_data = body.list[pair_key];
for (let b = 0; b < pair_data.bids.length; b++) {
buys.push({
price: parseFloat(pair_data.bids[b][0]) || 0,
quantity: parseFloat(pair_data.bids[b][1]) || 0
});
}
for (let s = 0; s < pair_data.asks.length; s++) {
sells.push({
price: parseFloat(pair_data.asks[s][0]) || 0,
quantity: parseFloat(pair_data.asks[s][1]) || 0
});
}
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
});
}
module.exports = {
market_name: 'Qutrade',
market_logo: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAhFBMVEUAAAAuSVwvR14vSFwwSF0wSF0wSF0wSF4xR14wR10wSF0vSF0uQ14xR1swSV0vSF0wSF0vSF0vRV4wR10vSF0vSF0xSVsvSV0wSlwxSF0wR1wuSFwwSF0vSV0wSl0vSF4uSFcyRmQuSVg6R2UsRGAxSFwwR1wySlswSF0xSlsyR18uR1sSei0+AAAAKHRSTlMAUg3n3KqdSC+jl0xCHgX89/LPvrOSiYR9d2VbWDwrJhfr2o1rUBQITdwwpgAAAJxJREFUGNNtj0kOgzAUQ02ANMxzmSmdHXr/+zWgZte3sfT99CVj59LkZNG8YDnT9X2X7HHQLW+151p9QhNOwdiadw7ASEaweEzhUCbAaQaWEREnBBTAvOUCLgGGqGh63lyv3ByAtTGQ6ivWbf8tKDHoGA9lLNMnISMIXcLikE+g1509nJhNJgLW4lgE1aa/KfSk9NjCkvgkM1/hH1/r4gv6hEKdhQAAAABJRU5ErkJggg==',
market_url_template: market_url_template,
market_url_case: 'l',
get_data: function(settings, cb) {
get_orders(settings.coin, settings.exchange, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(settings.coin, settings.exchange, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, function(summary_error, stats) {
if (summary_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: null});
else
return cb(summary_error, null);
});
} else
return cb(trade_error, null);
});
} else
return cb(order_error, null);
});
}
};
+143
View File
@@ -0,0 +1,143 @@
const request = require('postman-request');
const base_url = 'https://yobit.net/api/3';
const market_url_template = 'https://yobit.net/en/trade/{coin}/{base}';
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
const rateLimitLib = require('../ratelimit');
const rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
function get_summary(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/ticker/' + coin + '_' + exchange;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.success == 0)
return cb((body.error != null ? body.error : api_error_msg), null);
else {
try {
const prefix = body[coin + '_' + exchange];
const summary = {
'high': parseFloat(prefix.high) || 0,
'low': parseFloat(prefix.low) || 0,
'volume': parseFloat(prefix.vol) || 0,
'bid': parseFloat(prefix.buy) || 0,
'ask': parseFloat(prefix.sell) || 0,
'last': parseFloat(prefix.last) || 0
};
return cb(null, summary);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_trades(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/trades/' + coin + '_' + exchange;
// pause for 2 seconds before continuing
rateLimit.schedule(function() {
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null);
else if (body.success == 0)
return cb((body.error != null ? body.error : api_error_msg), null);
else {
try {
const prefix = body[coin + '_' + exchange];
let trades = [];
for (let t = 0; t < prefix.length; t++) {
trades.push({
ordertype: (prefix[t].type.toLowerCase() == 'bid' ? 'BUY' : 'SELL'),
price: parseFloat(prefix[t].price) || 0,
quantity: parseFloat(prefix[t].amount) || 0,
timestamp: parseInt(prefix[t].timestamp)
});
}
return cb(null, trades);
} catch(err) {
return cb(api_error_msg, null);
}
}
});
});
}
function get_orders(coin, exchange, api_error_msg, cb) {
const req_url = base_url + '/depth/' + coin + '_' + exchange;
// NOTE: no need to pause here because this is the first api call
request({uri: req_url, json: true}, function (error, response, body) {
if (error)
return cb(error, null, null);
else if (body == null || body == '' || typeof body !== 'object')
return cb(api_error_msg, null, null);
else if (body.success == 0)
return cb((body.error != null ? body.error : api_error_msg), null, null);
else {
try {
const prefix = body[coin + '_' + exchange];
let buys = [];
let sells = [];
for (let b = 0; b < prefix.bids.length; b++) {
buys.push({
price: parseFloat(prefix.bids[b][0]) || 0,
quantity: parseFloat(prefix.bids[b][1]) || 0
});
}
for (let s = 0; s < prefix.asks.length; s++) {
sells.push({
price: parseFloat(prefix.asks[s][0]) || 0,
quantity: parseFloat(prefix.asks[s][1]) || 0
});
}
return cb(null, buys, sells);
} catch(err) {
return cb(api_error_msg, null, null);
}
}
});
}
module.exports = {
market_name: 'Yobit',
market_logo: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAEsUExURQCZ2ACV1gCY2ACO1ACR1QCT1gCP1AKa2AGZ2AOa2QCX1wOa2AGa2ACS1QCU1gCV1wSb2QCY1wGV16Pc8tLu+Q6c2QCa2ASa2Ruk3DKt4AKZ2Aud2nrL61y/5gGS1QOb2WLB6Cyr3wOW1wSZ2GrE6XrK6zKu4EC04lG65eH1+1C75bjk9Syq3s7t+HjK64DN7ACQ1eT2/AOY2Lnk9Fq+55PV70y45Kne8hCd2sXq98vs+IXN7IrQ7YvR7gOR1ZnX8ASa2FG35Aec2WDB5wmd2tXw+QCM0zuu4Aab2QOO1AKS1ZXW70a24wGX153Z8ard8giY2Aub2QWb2bvm9cTp9mbC6GXC6MPo9h6j3Cap3iKo3iGo3s3s+Cus34nR7d3z+n3M7ACQ1Nry+tjy+pKA2eoAAADASURBVBjTY2AgDLjZgQQnkObkFuAAMsX4+HkYGHiZ2Fl5WVmYgAL8MuqsnIJxUSxmwuZ6yoI8DKwahqLMCcGeoa6O7sLaSlIM8sx+3hHxogFJkcyMbFZavAwcRoEhyT7MsTEcnE52tjZsDAwCBmHhib7RIkwOLmym+kABTjkTf68gIUtnNzYLTTU+oACLgjGLh5COiL21rior0FEcXBKSXBw8jNKyKoogPhBwMQIJdiYWFkYIn4EDTHNwirMzEAMA6McVLdcDhkkAAAAASUVORK5CYII=',
market_url_template: market_url_template,
market_url_case: 'u',
get_data: function(settings, cb) {
// ensure coin info is lowercase
settings.coin = settings.coin.toLowerCase();
settings.exchange = settings.exchange.toLowerCase();
get_orders(settings.coin, settings.exchange, settings.api_error_msg, function(order_error, buys, sells) {
if (order_error == null) {
get_trades(settings.coin, settings.exchange, settings.api_error_msg, function(trade_error, trades) {
if (trade_error == null) {
get_summary(settings.coin, settings.exchange, settings.api_error_msg, function(summary_error, stats) {
if (summary_error == null)
return cb(null, {buys: buys, sells: sells, trades: trades, stats: stats, chartdata: null});
else
return cb(summary_error, null);
});
} else
return cb(trade_error, null);
});
} else
return cb(order_error, null);
});
}
};
+39
View File
@@ -0,0 +1,39 @@
const http = require('http');
const settings = require('./settings');
const expected = settings.block_page.genesis_block;
let state = {status:'offline',chain:'NRB',height:null};
function rpc(method, params) {
return new Promise((resolve,reject)=>{
const data=JSON.stringify({id:'nerbus-health',method,params});
const r=http.request({host:settings.wallet.host,port:settings.wallet.port,method:'POST',
auth:settings.wallet.username+':'+settings.wallet.password,
headers:{'Content-Type':'application/json','Content-Length':Buffer.byteLength(data)}}, res=>{
let raw='';res.on('data',d=>raw+=d);res.on('end',()=>{
try { const v=JSON.parse(raw);if(v.error) reject(Error('RPC error'));else resolve(v.result); }
catch(e){reject(e);}
});
});
r.setTimeout(3000,()=>r.destroy(Error('RPC timeout')));
r.on('error',reject);r.end(data);
});
}
async function probe() {
try {
if(await rpc('getblockhash',[0])!==expected) {
state={status:'wrong-network',chain:'NRB',height:null};return;
}
state={status:'online',chain:'NRB',height:await rpc('getblockcount',[])};
} catch (_) { state={status:'offline',chain:'NRB',height:null}; }
}
module.exports=function(app) {
probe();setInterval(probe,10000).unref();
app.get('/healthz',(req,res)=>res.json({explorer:'Nerbus',...state}));
app.use((req,res,next)=>{res.locals.nerbusState=state;
if(state.status!=='online' && req.path==='/ext/getsummary')
return res.json({status:state.status,difficulty:'-',difficultyHybrid:'',supply:'-',hashrate:'-',
connections:'-',blockcount:'-',lastPrice:'0',lastUSDPrice:'0',marketcap:'0.00',usdMarketcap:'0.00'});
if(state.status!=='online' && req.path.startsWith('/api/'))
return res.status(503).json({error:'Nerbus node is offline; network launch pending'});
next();
});
};
+33
View File
@@ -0,0 +1,33 @@
var rpc = require('./jsonrpc');
function Client(opts) {
this.rpc = new rpc.Client(opts);
};
Client.prototype.cmd = function() {
var args = [].slice.call(arguments);
var cmd = args.shift();
callRpc(cmd, args, this.rpc);
};
function callRpc (cmd, args, rpc) {
var fn = args[args.length - 1];
// if the last argument is a callback, pop it from the args list
if (typeof fn === 'function')
args.pop();
else
fn = function () {};
rpc.call(cmd, args, function () {
var args = [].slice.call(arguments);
args.unshift(null);
fn.apply(this, args);
}, function(err) {
fn(err);
});
};
module.exports.Client = Client;
+351
View File
@@ -0,0 +1,351 @@
var onode = require('./node'),
express = require('express'),
settings = require('./settings');
module.exports = function() {
function express_app() {
var app = express();
app.get('/{*splat}', hasAccess, function(req, res) {
var method = req.path.substring(1, req.path.length);
if ('undefined' != typeof requires_passphrase[method]) {
if (wallet_passphrase)
client.walletPassphrase(wallet_passphrase, 10);
else
res.send('A wallet passphrase is needed and has not been set.');
}
const query_parameters = req.query;
let params = [];
Object.keys(query_parameters).forEach(function(parameter) {
let param = query_parameters[parameter];
if (!isNaN(param))
param = parseFloat(param);
params.push(param);
});
var command = [];
switch (method) {
case 'getnetworkhashps':
case 'getmininginfo':
case 'getdifficulty':
case 'getconnectioncount':
case 'getblockcount':
case 'getblockhash':
case 'getblock':
case 'getrawtransaction':
case 'getsupply':
case 'getinfo':
case 'getblockchaininfo':
case 'getpeerinfo':
case 'gettxoutsetinfo':
case 'getmaxmoney':
case 'getmaxvote':
case 'getvote':
case 'getphase':
case 'getreward':
case 'getnextrewardestimate':
case 'getnextrewardwhenstr':
case 'getvotelist':
case 'getmasternodecount':
case 'getmasternodelist':
case 'verifymessage':
case 'sendmany':
command = specialApiCase(method, query_parameters);
break;
default:
command = [{
method: method,
params: params
}];
break;
}
client.cmd(command, function(err, response) {
if (err) {
console.log(err);
res.send(`${settings.localization.ex_error}: ${settings.localization.check_console}`);
} else {
if (typeof response === 'object')
res.json(response);
else {
res.setHeader('content-type', 'text/plain');
res.end(response.toString());
}
}
});
});
function hasAccess(req, res, next) {
var method = req.path.substring(1, req.path.length);
var method_enabled = false;
// check if this is a "normal" api method
if (settings.api_page.public_apis.rpc[method] != null) {
// check the enabled property of this normal method
method_enabled = settings.api_page.public_apis.rpc[method].enabled;
} else {
// look for this method in the list of blockchain specific features
Object.keys(settings.blockchain_specific).forEach(function(key, index, map) {
// check if this feature is enabled and has a definition for this api cmd
if (settings.blockchain_specific[key].enabled == true && settings.blockchain_specific[key]['public_apis'] != null && settings.blockchain_specific[key]['public_apis'][method] != null) {
// check the enabled properly of this blockchain specific method
method_enabled = settings.blockchain_specific[key]['public_apis'][method].enabled;
}
});
}
// only show disabled msg for outside calls. internal calls should always go through
if ((!settings.api_page.enabled || method_enabled == null || !method_enabled) && req.headers.host.indexOf('127.0.0.1') == -1)
res.end(settings.localization.method_disabled);
else if (method == 'getnetworkhashps' && !settings.shared_pages.show_hashrate) {
// getnetworkhashps requires show_hashrate to be enabled or else hashrate cannot be returned
res.end('-');
} else {
if (accesslist.type == 'all')
return next();
if ('undefined' == typeof accesslist[method]) {
if (accesslist.type == 'only')
res.end('This method is restricted');
else
return next();
} else {
if (accesslist[method] == true)
return next();
else
res.end('This method is restricted');
}
}
}
function prepareRpcCommand(cmd, addParams) {
var method_name = '';
var params = addParams || [];
// Check for null/blank string
if (cmd != null && cmd.trim() != '') {
// Split cmd by spaces
var split = cmd.split(' ');
for (i=0; i<split.length; i++) {
if (i==0)
method_name = split[i];
else
params.push(split[i]);
}
}
return { method: method_name, parameters: params };
}
function specialApiCase(method_name, query_parameters) {
var params = [];
switch (method_name) {
case 'getnetworkhashps':
case 'getmininginfo':
case 'getdifficulty':
case 'getconnectioncount':
case 'getblockcount':
case 'getinfo':
case 'getblockchaininfo':
case 'getpeerinfo':
case 'gettxoutsetinfo':
case 'getvotelist':
case 'getmasternodecount':
case 'getmasternodelist':
var cmd = prepareRpcCommand(settings.api_cmds[method_name]);
method_name = cmd.method;
params = cmd.parameters;
break;
case 'getmaxmoney':
case 'getmaxvote':
case 'getvote':
case 'getphase':
case 'getreward':
case 'getnextrewardestimate':
case 'getnextrewardwhenstr':
case 'getsupply':
var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds[method_name]);
method_name = cmd.method;
params = cmd.parameters;
break;
case 'getblockhash':
Object.keys(query_parameters).forEach(function(parameter) {
if (parameter == 'height' || parameter == 'index')
params.push(parseInt(query_parameters[parameter]));
});
var cmd = prepareRpcCommand(settings.api_cmds.getblockhash, params);
method_name = cmd.method;
params = cmd.parameters;
break;
case 'getblock':
Object.keys(query_parameters).forEach(function(parameter) {
if (parameter == 'hash')
params.push(query_parameters[parameter]);
});
var cmd = prepareRpcCommand(settings.api_cmds.getblock, params);
method_name = cmd.method;
params = cmd.parameters;
break;
case 'getrawtransaction':
Object.keys(query_parameters).forEach(function(parameter) {
if (parameter == 'txid')
params.push(query_parameters[parameter]);
else if (parameter == 'decrypt')
params.push(parseInt(query_parameters[parameter]));
});
var cmd = prepareRpcCommand(settings.api_cmds.getrawtransaction, params);
method_name = cmd.method;
params = cmd.parameters;
break;
case 'verifymessage':
Object.keys(query_parameters).forEach(function(parameter) {
if (parameter == 'address' || parameter == 'message')
params.push(query_parameters[parameter]);
if (parameter == 'signature') {
let param = decodeURIComponent(query_parameters[parameter]);
while (param.indexOf(' ') > -1)
param = param.replace(' ', '+');
params.push(param);
}
});
var cmd = prepareRpcCommand(settings.api_cmds.verifymessage, params);
method_name = cmd.method;
params = cmd.parameters;
break;
case 'sendmany':
var after_account = false;
var before_min_conf = true;
var address_info = {};
Object.keys(query_parameters).forEach(function(parameter) {
if (parameter == 'minconf') {
before_min_conf = false;
params.push(address_info);
}
let param = query_parameters[parameter];
if (!isNaN(param))
param = parseFloat(param);
if (after_account && before_min_conf)
address_info[parameter] = param;
else
params.push(param);
if (parameter == 'account')
after_account = true;
});
if (before_min_conf)
params.push(address_info);
break;
}
return [{
method: method_name,
params: params
}];
}
return app;
};
var accesslist = {};
var client = {};
var wallet_passphrase = null;
var requires_passphrase = {
'dumpprivkey': true,
'importprivkey': true,
'keypoolrefill': true,
'sendfrom': true,
'sendmany': true,
'sendtoaddress': true,
'signmessage': true,
'signrawtransaction': true
};
accesslist.type = 'all';
function setAccess(type, access_list) {
// reset
accesslist = {};
accesslist.type = type;
if (type == "only") {
for (i = 0; i < access_list.length; i++)
accesslist[access_list[i]] = true;
}
if (type == "restrict") {
for (i = 0; i < access_list.length; i++)
accesslist[access_list[i]] = false;
}
// default is for security reasons. Prevents accidental theft of coins/attack
if (type == 'default-safe') {
var restrict_list = ['dumpprivkey', 'walletpassphrasechange', 'stop'];
accesslist.type = 'restrict';
for (i = 0; i < restrict_list.length; i++)
accesslist[restrict_list[i]] = false;
}
if (type == 'read-only') {
var restrict_list = ['addmultisigaddress', 'addnode', 'backupwallet', 'createmultisig', 'createrawtransaction', 'encryptwallet', 'importprivkey', 'keypoolrefill', 'lockunspent', 'move', 'sendfrom', 'sendmany', 'sendrawtransaction', 'sendtoaddress', 'setaccount', 'setgenerate', 'settxfee', 'signmessage', 'signrawtransaction', 'stop', 'submitblock', 'walletlock', 'walletpassphrasechange'];
accesslist.type = 'restrict';
for (i = 0; i < restrict_list.length; i++)
accesslist[restrict_list[i]] = false;
}
};
function setWalletDetails(details) {
if ('undefined' == typeof details.rpc)
client = new onode.Client(details);
else
client = details;
};
function setWalletPassphrase(passphrase) {
wallet_passphrase = passphrase;
};
return {
app: express_app(),
setAccess: setAccess,
setWalletDetails: setWalletDetails,
setWalletPassphrase: setWalletPassphrase
}
}();
+52
View File
@@ -0,0 +1,52 @@
// Initialize the rate limiting class from Matteo Agosti via https://www.matteoagosti.com/blog/2013/01/22/rate-limiting-function-calls-in-javascript/
var RateLimit = (function() {
var RateLimit = function(maxOps, interval, allowBursts) {
this._maxRate = allowBursts ? maxOps : maxOps / interval;
this._interval = interval;
this._allowBursts = allowBursts;
this._numOps = 0;
this._start = new Date().getTime();
this._queue = [];
};
RateLimit.prototype.schedule = function(fn) {
var that = this,
rate = 0,
now = new Date().getTime(),
elapsed = now - this._start;
if (elapsed > this._interval) {
this._numOps = 0;
this._start = now;
}
rate = this._numOps / (this._allowBursts ? 1 : elapsed);
if (rate < this._maxRate) {
if (this._queue.length === 0) {
this._numOps++;
fn();
} else {
if (fn)
this._queue.push(fn);
this._numOps++;
this._queue.shift()();
}
} else {
if (fn)
this._queue.push(fn);
setTimeout(function() {
that.schedule();
}, 1 / this._maxRate);
}
};
return RateLimit;
})();
module.exports = {
RateLimit: RateLimit
};
+2363
View File
File diff suppressed because it is too large. Load diff
+253
View File
@@ -0,0 +1,253 @@
/* This file must be valid JSON. But comments are allowed */
{
// global
"difficulty": "Difficulty",
"masternodecount": "Masternodes",
"network": "Network",
"height": "Height",
"timestamp": "Timestamp",
"size": "Size",
"transactions": "Transactions",
"total_sent": "Total Sent",
"total_received": "Total Received",
"confirmations": "Confirmations",
"total": "Total",
"total_top_100": "Top 1-100 Total",
"bits": "Bits",
"nonce": "Nonce",
"new_coins": "New Coins",
"proof_of_stake": "PoS",
"hidden_address": "Hidden Address",
"hidden_sender": "Hidden Sender",
"hidden_recipient": "Hidden Recipient",
"unknown_address": "Unknown Address",
"unknown_sender": "Unknown Sender",
"unknown_recipient": "Unknown Recipient",
"last_updated": "Last Updated",
"initial_index_alert": "Blockchain data is currently being synchronized. You may browse the site during this time, but keep in mind that data may not yet be fully accurate and some functionality may not work until synchronization is complete.",
"please_wait": "Please wait",
"creating_initial_entry": "Creating initial {1} entry",
"entry_created_successfully": "Initial {1} entry for {2} created successfully",
"method_disabled": "This method is disabled",
"compiling_css": "Compiling CSS",
"installing_module": "Installing {1} module",
"restoring_backup": "Restoring backup",
"extracting_backup_files": "Extracting backup files",
"explorer_shutting_down": "Explorer shutting down",
"initializing_database": "Initializing database",
"downloading_newest_explorer_code": "Downloading newest explorer code",
"check_outdated_packages": "Checking for outdated packages",
"updating_explorer_packages": "Updating out-of-date explorer packages",
"checking_webserver_running": "Checking if webserver is running",
"reloading_explorer": "Reloading the explorer",
"email_sent_successfully": "Email sent successfully",
"check_console": "Check your console",
"process_aborted": "Process aborted",
"nothing_was_deleted": "Nothing was deleted",
"nothing_was_restored": "Nothing was restored",
// prompts
"are_you_sure": "Are you sure you want to do this? [y/n]",
"short_yes": "y",
"long_yes": "yes",
// menu items
"menu_explorer": "Explorer",
"menu_api": "API",
"menu_markets": "Markets",
"menu_richlist": "Top 100",
"menu_reward": "Reward",
"menu_movement": "Movement",
"menu_node": "Nodes",
"menu_network": "Network",
"menu_claim_address": "Claim Address",
"menu_orphans": "Orphaned Blocks",
// explorer view
"ex_title": "{1} Block Explorer",
"ex_description": "A listing of all verified {1} transactions",
"ex_search_title": "Search",
"ex_search_button": "Search",
"ex_search_message": "Search by block height, block hash, tx hash or address",
"ex_error": "Error",
"ex_warning": "Warning",
"ex_search_error": "Search found no results for: ",
"ex_latest_transactions": "Latest Transactions",
"ex_summary": "Block Summary",
"ex_supply": "Coin Supply",
"ex_block": "Block",
// transaction view
"tx_title": "{1} Transaction Details",
"tx_description": "Viewing tx data from {1} block # {2}",
"tx_block_hash": "Block Hash",
"tx_recipients": "Recipients",
"tx_contributors": "Input Addresses",
"tx_hash": "Tx Hash",
"tx_address": "Address",
"tx_nonstandard": "NONSTANDARD TX",
"view_raw_tx_data": "View Raw Transaction Data",
"view_block": "View Block",
// block view
"block_title": "{1} Block Details",
"block_description": "Viewing block data from {1} block # {2}",
"block_previous": "Previous Block",
"block_next": "Next Block",
"block_genesis": "GENESIS",
"view_raw_block_data": "View Raw Block Data",
"view_tx": "View Transaction",
// error view
"error_title": "{1} Block Explorer Error",
"error_description": "The page you are looking for cannot be found",
"error_description_alt": "An error occurred which prevented the page from loading correctly",
"error_not_found": "Not Found",
// address view
"a_title": "{1} Wallet Address Details",
"a_description": "Viewing balance and transaction data from {1} address {2}",
"a_menu_showing": "Showing last",
"a_menu_txs": "transactions",
"a_menu_all": "All",
"a_qr": "QR Code",
// masternode view
"mn_title": "{1} Masternodes",
"mn_description": "A listing of all masternodes known to be active on the {1} network",
"mn_masternode_list": "Masternode List",
// movement view
"move_title": "{1} Coin Movements",
"move_description": "A listing of larger movements where {1} or more {2} coins were sent in a single transaction",
// richlist view
"rl_title": "Top {1} Coin Holders",
"rl_description": "A listing of the richest {1} wallet addresses and breakdown of the current coin distribution",
"rl_received_coins": "Top 100 - Received Coins",
"rl_current_balance": "Top 100 - Current Balance",
"rl_received": "Received",
"rl_balance": "Balance",
"rl_wealth": "Wealth Distribution",
"rl_top25": "Top 1-25",
"rl_top50": "Top 26-50",
"rl_top75": "Top 51-75",
"rl_top100": "Top 76-100",
"rl_hundredplus": "101+",
// network view
"net_title": "{1} Network Peers",
"net_description": "A listing of {1} network peers that have connected to the explorer node in the last 24 hours",
"net_addnodes": "Add Nodes",
"net_connections": "Connections",
"net_address": "Address",
"net_protocol": "Protocol",
"net_subversion": "Sub-version",
"net_country": "Country",
// api view
"api_title": "{1} Public API",
"api_description": "A listing of public API endpoints for retrieving {1} coin data from the network without the need for a local wallet",
"api_documentation": "API Documentation",
"api_calls": "API Calls",
"api_getnetworkhashps": "Returns the current network hashrate. (hash/s)",
"api_getdifficulty": "Returns the current difficulty.",
"api_getconnectioncount": "Returns the number of connections the block explorer has to other nodes.",
"api_getmasternodelist": "Returns the complete list of masternodes on the network.",
"api_getmasternodecount": "Returns the total number of masternodes on the network.",
"api_getvotelist": "Returns the current vote list.",
"api_getblockcount": "Returns the current block index.",
"api_getblockhash": "Returns the hash of the block at [index]; index 0 is the genesis block.",
"api_getblock": "Returns information about the block with the given hash.",
"api_getrawtransaction": "Returns raw transaction representation for given transaction id. decrypt can be set to 0(false) or 1(true).",
"api_getmaxmoney": "Returns the maximum possible money supply.",
"api_getmaxvote": "Returns the maximum allowed vote for the current phase of voting.",
"api_getvote": "Returns the current block reward vote setting.",
"api_getphase": "Returns the current voting phase ('Mint', 'Limit' or 'Sustain').",
"api_getreward": "Returns the current block reward, which has been decided democratically in the previous round of block reward voting.",
"api_getsupply": "Returns the current money supply.",
"api_getnextrewardestimate": "Returns an estimate for the next block reward based on the current state of decentralized voting.",
"api_getnextrewardwhenstr": "Returns a string describing how long until the votes are tallied and the next block reward is computed.",
// markets view
"mkt_title": "{1} Market Details",
"mkt_description": "Viewing {1} market data for the {2} exchange",
"mkt_hours": "24 hours",
"mkt_view_chart": "View 24 hour summary",
"mkt_view_summary": "View 24 hour chart",
"mkt_no_chart": "Chart data is not available via markets API",
"mkt_high": "High",
"mkt_low": "Low",
"mkt_volume": "Volume",
"mkt_top_bid": "Top Bid",
"mkt_top_ask": "Top Ask",
"mkt_last": "Last Price",
"mkt_yesterday": "Yesterday",
"mkt_change": "Change",
"mkt_sell_orders": "Sell Orders",
"mkt_buy_orders": "Buy Orders",
"mkt_price": "Price",
"mkt_amount": "Amount",
"mkt_total": "Total",
"mkt_trade_history": "Trade History",
"mkt_type": "Type",
"mkt_time_stamp": "Time Stamp",
"mkt_select": "Market Select",
"mkt_unexpected_api_data": "Received unexpected API data response",
// claim address view
"claim_title": "{1} Wallet Address Claim",
"claim_description": "Verify ownership of your {1} wallet address and set a custom display name in the explorer",
// orphans view
"orphan_title": "{1} Orphaned Blocks",
"orphan_description": "A listing of valid blocks that have been orphaned and do not belong to the main blockchain",
"orphan_block_list": "Orphaned Block List",
"orphan_block_hash": "Orphaned Block Hash",
"orphan_actual_block": "Actual Block",
"orphan_prev_block": "Previous Block",
"orphan_next_block": "Next Block",
"view_orphan": "View Orphaned Block",
// heavycoin rewards view
"heavy_title": "{1} Reward/Voting Details",
"heavy_description": "Viewing {1} voting data and coin reward change details",
"heavy_reward_voting_info": "Reward/voting information",
"heavy_vote": "Vote",
"heavy_cap": "Coin Cap",
"heavy_phase": "Phase",
"heavy_maxvote": "Max Vote",
"heavy_reward": "Reward",
"heavy_current": "Current Reward",
"heavy_estnext": "Est. Next",
"heavy_changein": "Reward change in approximately",
"heavy_key": "Key",
"heavy_lastxvotes": "Last 20 votes",
// sync
"script_launched": "Script launched with pid",
"stopping_sync_process": "Stopping sync process",
"finding_earliest_orphan": "Finding the earliest orphaned blockindex",
"calculating_market_price": "Calculating market price",
"syncing_blocks": "Syncing blocks",
"syncing_peers": "Syncing peers",
"syncing_masternodes": "Syncing masternodes",
"syncing_markets": "Syncing markets",
"checking_blocks": "Checking blocks",
"calculating_tx_count": "Calculating tx count",
"finding_last_blockindex": "Finding last blockindex",
"path_cannot_be_found": "'{1}' cannot be found",
// settings
"deprecated_setting": "Deprecated setting '{1}' has been mapped to the new location '{2}'. Be sure to make this change in settings.json as the old setting will be removed in a future release",
"unknown_setting": "Unknown setting '{1}' has been ignored",
"missing_setting": "Setting '{1}' is missing. Loading default value",
"continuing_using_defaults": "Continuing using defaults",
"missing_settings_file": "The {1} file is missing",
"error_processing_settings": "There was an error processing the {1} file",
// locale
"locale_lowercase_req": "Locale strings must start with a lowercase character",
"locale_unknown_string": "Unknown Locale String",
"locale_not_exists": "This setting doesn't exist or was removed"
}
+13
View File
@@ -0,0 +1,13 @@
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const D0 = () => mongoose.Types.Decimal128.fromString('0');
const AddressSchema = new Schema({
a_id: { type: String, unique: true, index: true},
name: { type: String }, // no longer used but cannot be removed or else older versions that have data here will not be able to auto move claim name data to the new claimaddress collection
received: { type: Schema.Types.Decimal128, default: D0, index: true },
sent: { type: Schema.Types.Decimal128, default: D0, index: true },
balance: {type: Schema.Types.Decimal128, default: D0, index: true}
}, {id: false});
module.exports = mongoose.model('Address', AddressSchema);
+14
View File
@@ -0,0 +1,14 @@
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const D0 = () => mongoose.Types.Decimal128.fromString('0');
const AddressTXSchema = new Schema({
a_id: { type: String, index: true},
blockindex: {type: Number, default: 0, index: true},
txid: { type: String, lowercase: true, index: true},
amount: { type: Schema.Types.Decimal128, default: D0, index: true}
}, {id: false});
AddressTXSchema.index({a_id: 1, blockindex: -1});
module.exports = mongoose.model('AddressTx', AddressTXSchema);
+9
View File
@@ -0,0 +1,9 @@
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var ClaimAddressSchema = new Schema({
a_id: {type: String, unique: true, index: true},
claim_name: {type: String, default: '', index: true}
}, {id: false});
module.exports = mongoose.model('ClaimAddress', ClaimAddressSchema);
+17
View File
@@ -0,0 +1,17 @@
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var HeavySchema = new Schema({
coin: { type: String },
lvote: { type: Number, default: 0 },
reward: { type: Number, default: 0 },
supply: { type: Number, default: 0 },
cap: { type: Number, default: 0 },
estnext: { type: Number, default: 0 },
phase: { type: String, default: 'N/A'},
maxvote: { type: Number, default: 0 },
nextin: { type: String, default: 'N/A'},
votes: { type: Array, default: [] }
});
module.exports = mongoose.model('Heavy', HeavySchema);
+15
View File
@@ -0,0 +1,15 @@
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var MarketsSchema = new Schema({
market: { type: String, index: true },
coin_symbol: { type: String },
pair_symbol: { type: String },
summary: { type: Object, default: {} },
chartdata: { type: Array, default: [] },
buys: { type: Array, default: [] },
sells: { type: Array, default: [] },
history: { type: Array, default: [] },
});
module.exports = mongoose.model('Markets', MarketsSchema);
+20
View File
@@ -0,0 +1,20 @@
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var MasternodeSchema = new Schema({
rank: { type: Number, default: 0 },
network: { type: String, default: "" },
txhash: { type: String, default: "" },
outidx : { type: Number, default: 0},
status : { type: String, default: "" },
addr: { type: String, index: true },
version : { type: Number, default: 0},
lastseen: { type: Number, default: 0 },
activetime: { type: Number, default: 0 },
lastpaid: { type: Number, default: 0 },
claim_name: { type: String, default: '', index: true },
ip_address: { type: String, default: '', index: true },
last_paid_block: {type: Number, default: 0}
}, {id: false});
module.exports = mongoose.model('Masternode', MasternodeSchema);
+12
View File
@@ -0,0 +1,12 @@
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var NetworkHistorySchema = new Schema({
blockindex: {type: Number, default: 0, index: true},
nethash: { type: Number, default: 0 },
difficulty_pow: { type: Number, default: 0 },
difficulty_pos: { type: Number, default: 0 },
timestamp: { type: Number, default: 0 }
}, {id: false});
module.exports = mongoose.model('NetworkHistory', NetworkHistorySchema);
+12
View File
@@ -0,0 +1,12 @@
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var OrphanSchema = new Schema({
blockindex: {type: Number, default: 0, index: true},
orphan_blockhash: {type: String, unique: true, index: true},
good_blockhash: {type: String, index: true},
prev_blockhash: {type: String, index: true},
next_blockhash: {type: String, index: true}
}, {id: false});
module.exports = mongoose.model('Orphan', OrphanSchema);
+32
View File
@@ -0,0 +1,32 @@
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var PeersSchema = new Schema({
createdAt: { type: Date, expires: 86400, default: Date.now() },
address: { type: String, default: "", index: true },
port: { type: String, default: "" },
protocol: { type: String, default: "" },
version: { type: String, default: "" },
country: { type: String, default: "" },
country_code: { type: String, default: "" },
ipv6: { type: Boolean, default: false },
table_type: {
type: String,
enum: ["C", "A", "O"], // "C"=Connections, "A"=AddNodes, "O"=OneTry
default: "C",
index: true
}
});
PeersSchema.index({
table_type: 1,
ipv6: 1,
address: 1,
protocol: -1,
port: 1
}, {
name: 'peer_compound_idx',
background: true
});
module.exports = mongoose.model('Peers', PeersSchema);
+11
View File
@@ -0,0 +1,11 @@
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var RichlistSchema = new Schema({
coin: { type: String },
received: { type: Array, default: [] },
balance: { type: Array, default: [] },
burned: { type: Array, default: [] }
});
module.exports = mongoose.model('Richlist', RichlistSchema);
+26
View File
@@ -0,0 +1,26 @@
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const D0 = () => mongoose.Types.Decimal128.fromString('0');
const StatsSchema = new Schema({
coin: { type: String },
count: { type: Number, default: 1 },
last: { type: Number, default: 1 },
supply: { type: Schema.Types.Decimal128, default: D0 },
txes: { type: Number, default: 0 },
connections: { type: Number, default: 0 },
last_price: { type: Schema.Types.Decimal128, default: D0 },
last_usd_price: { type: Schema.Types.Decimal128, default: D0 },
blockchain_last_updated: { type: Number, default: 0 },
reward_last_updated: { type: Number, default: 0 },
masternodes_last_updated: { type: Number, default: 0 },
network_last_updated: { type: Number, default: 0 },
richlist_last_updated: { type: Number, default: 0 },
markets_last_updated: { type: Number, default: 0 },
orphan_index: { type: Number, default: 0 },
orphan_current: { type: Number, default: 0 },
newer_claim_address: { type: Boolean, default: false },
address_count: { type: Number, default: 0 }
});
module.exports = mongoose.model('coinstats', StatsSchema);
+20
View File
@@ -0,0 +1,20 @@
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const D0 = () => mongoose.Types.Decimal128.fromString('0');
const TxSchema = new Schema({
txid: { type: String, lowercase: true, unique: true, index: true},
vin: { type: Array, default: [] },
vout: { type: Array, default: [] },
total: { type: Schema.Types.Decimal128, default: D0, index: true },
timestamp: { type: Number, default: 0, index: true },
blockhash: { type: String, index: true },
blockindex: {type: Number, default: 0, index: true},
tx_type: { type: String, default: null },
op_return: { type: String, default: null },
algo: { type: String, default: null }
}, {id: false});
TxSchema.index({total: 1, total: -1, blockindex: 1, blockindex: -1});
module.exports = mongoose.model('Tx', TxSchema);
+61
View File
@@ -0,0 +1,61 @@
{
"name": "explorer",
"version": "1.103.0",
"private": true,
"scripts": {
"start": "node --stack-size=10000 ./bin/cluster",
"stop": "node ./scripts/stop_explorer.js",
"start-instance": "npm run prestart && node --stack-size=10000 ./bin/cluster 1",
"start-forever": "npm run prestart \"forever production\"",
"stop-forever": "forever stop \"explorer\"",
"reload-forever": "npm run prestart \"forever production reload\"",
"start-pm2": "npm run prestart \"pm2 production\"",
"start-pm2-debug": "npm run prestart \"pm2 development\" && pm2 logs",
"stop-pm2": "pm2 stop explorer",
"reload-pm2": "npm run prestart \"pm2 production reload\"",
"test": "node ./node_modules/jasmine/bin/jasmine.js test/*Spec.js",
"prestart": "node ./scripts/prestart.js",
"sync-blocks": "node ./scripts/sync.js index update",
"sync-markets": "node ./scripts/sync.js market",
"sync-peers": "node ./scripts/sync.js peers",
"sync-masternodes": "node ./scripts/sync.js masternodes",
"check-blocks": "node ./scripts/sync.js index check",
"reindex": "node ./scripts/sync.js index reindex",
"reindex-rich": "node ./scripts/sync.js index reindex-rich",
"reindex-txcount": "node ./scripts/sync.js index reindex-txcount",
"reindex-last": "node ./scripts/sync.js index reindex-last",
"create-backup": "node ./scripts/create_backup.js",
"restore-backup": "node ./scripts/restore_backup.js",
"delete-database": "node ./scripts/delete_database.js",
"update-explorer": "node ./scripts/update_explorer.js",
"benchmark": "node ./scripts/benchmark.js"
},
"dependencies": {
"async": "^3.2.6",
"bad-words": "^4.0.0",
"cookie-parser": "^1.4.7",
"debug": "^4.4.0",
"decimal.js": "^10.6.0",
"express": "^5.1.0",
"intl": "^1.2.5",
"jsonminify": "^0.4.2",
"mongoose": "^9.2.4",
"morgan": "^1.10.0",
"postman-request": "^2.88.1-postman.42",
"pug": "~3.0.3",
"qr-image": "^3.2.0",
"sass": "^1.86.3",
"serve-favicon": "^2.5.0"
},
"devDependencies": {
"forever": "^4.0.3",
"jasmine": "^6.1.0",
"pm2": "^7.0.1"
},
"overrides": {
"qs": "6.16.0",
"postman-request": {
"uuid": "11.1.1"
}
}
}
+1
View File
@@ -0,0 +1 @@
This file is used to ensure the plugins folder syncs with git. It's safe to delete this file.
View File
Whitespace-only changes.
+1
View File
@@ -0,0 +1 @@
/* Add custom css rules here */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,83 @@
// Cerulean 5.1.3
// Bootswatch
// Variables
$text-shadow: 0 1px 0 rgba(0, 0, 0, .05) !default;
// Mixins
@mixin btn-shadow($color){
@include gradient-y-three-colors(tint-color($color, 16%), $color, 60%, shade-color($color, 6%));
}
// Navbar
.navbar {
@each $color, $value in $theme-colors {
&.bg-#{$color} {
@include btn-shadow($value);
}
}
}
.navbar-brand,
.nav-link {
text-shadow: $text-shadow;
}
// Buttons
.btn {
text-shadow: $text-shadow;
}
.btn-secondary {
color: $gray-700;
}
@each $color, $value in $theme-colors {
.btn-#{$color} {
@include btn-shadow($value);
}
}
// Typography
.text-secondary {
color: $gray-500 !important;
}
.bg-primary,
.bg-success,
.bg-info,
.bg-warning,
.bg-danger,
.bg-dark {
h1,
h2,
h3,
h4,
h5,
h6 {
color: $white;
}
}
// Navs
.dropdown-menu {
.dropdown-header {
color: $gray-600;
}
}
// Indicators
.badge {
&.bg-secondary,
&.bg-light {
color: $dark;
}
}
@@ -0,0 +1,61 @@
// Cerulean 5.1.3
// Bootswatch
$theme: "cerulean" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #e9ecef !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: #adb5bd !default;
$gray-600: #868e96 !default;
$gray-700: #495057 !default;
$gray-800: #343a40 !default;
$gray-900: #212529 !default;
$black: #000 !default;
$blue: #033c73 !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #c71c22 !default;
$orange: #fd7e14 !default;
$yellow: #dd5600 !default;
$green: #73a839 !default;
$teal: #20c997 !default;
$cyan: #2fa4e7 !default;
$primary: $cyan !default;
$secondary: $gray-200 !default;
$success: $green !default;
$info: $blue !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-100 !default;
$dark: $gray-800 !default;
$min-contrast-ratio: 2.75 !default;
// Body
$body-color: $gray-700 !default;
// Fonts
$headings-color: $cyan !default;
// Dropdowns
$dropdown-link-color: $body-color !default;
$dropdown-link-hover-color: $white !default;
$dropdown-link-hover-bg: $primary !default;
// Navbar
$navbar-dark-color: rgba($white, .8) !default;
$navbar-dark-hover-color: $white !default;
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
/*!
* Bootswatch v5.1.3
* Homepage: https://bootswatch.com
* Copyright 2012-2021 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/:root{--bs-blue:#033c73;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#e83e8c;--bs-red:#c71c22;--bs-orange:#fd7e14;--bs-yellow:#dd5600;--bs-green:#73a839;--bs-teal:#20c997;--bs-cyan:#2fa4e7;--bs-white:#fff;--bs-gray:#868e96;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#868e96;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#2fa4e7;--bs-secondary:#e9ecef;--bs-success:#73a839;--bs-info:#033c73;--bs-warning:#dd5600;--bs-danger:#c71c22;--bs-light:#f8f9fa;--bs-dark:#343a40;--bs-primary-rgb:47,164,231;--bs-secondary-rgb:233,236,239;--bs-success-rgb:115,168,57;--bs-info-rgb:3,60,115;--bs-warning-rgb:221,86,0;--bs-danger-rgb:199,28,34;--bs-light-rgb:248,249,250;--bs-dark-rgb:52,58,64;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:73,80,87;--bs-body-bg-rgb:255,255,255;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#495057;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:#2fa4e7}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#2fa4e7;text-decoration:underline}a:hover{color:#2683b9}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#868e96;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);lLine truncated
+35
View File
@@ -0,0 +1,35 @@
// Cosmo 5.1.3
// Bootswatch
// Variables
$web-font-path: "https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400;700&display=swap" !default;
@if $web-font-path {
@import url($web-font-path);
}
// Typography
body {
-webkit-font-smoothing: antialiased;
}
// Indicators
.badge {
&.bg-light {
color: $dark;
}
}
// Progress bars
.progress {
@include box-shadow(none);
.progress-bar {
font-size: 8px;
line-height: 8px;
}
}
+69
View File
@@ -0,0 +1,69 @@
// Cosmo 5.1.3
// Bootswatch
$theme: "cosmo" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #e9ecef !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: #adb5bd !default;
$gray-600: #868e96 !default;
$gray-700: #495057 !default;
$gray-800: #373a3c !default;
$gray-900: #212529 !default;
$black: #000 !default;
$blue: #2780e3 !default;
$indigo: #6610f2 !default;
$purple: #613d7c !default;
$pink: #e83e8c !default;
$red: #ff0039 !default;
$orange: #f0ad4e !default;
$yellow: #ff7518 !default;
$green: #3fb618 !default;
$teal: #20c997 !default;
$cyan: #9954bb !default;
$primary: $blue !default;
$secondary: $gray-800 !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-100 !default;
$dark: $gray-800 !default;
$min-contrast-ratio: 2.6 !default;
// Options
$enable-rounded: false !default;
// Body
$body-color: $gray-800 !default;
// Fonts
// stylelint-disable-next-line value-keyword-case
$font-family-sans-serif: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default;
$headings-font-weight: 400 !default;
// Navbar
$navbar-dark-hover-color: rgba($white, 1) !default;
$navbar-light-hover-color: rgba($black, .9) !default;
// Alerts
$alert-border-width: 0 !default;
// Progress bars
$progress-height: .5rem !default;
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
/*!
* Bootswatch v5.1.3
* Homepage: https://bootswatch.com
* Copyright 2012-2021 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/@import url(https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400;700&display=swap);:root{--bs-blue:#2780e3;--bs-indigo:#6610f2;--bs-purple:#613d7c;--bs-pink:#e83e8c;--bs-red:#ff0039;--bs-orange:#f0ad4e;--bs-yellow:#ff7518;--bs-green:#3fb618;--bs-teal:#20c997;--bs-cyan:#9954bb;--bs-white:#fff;--bs-gray:#868e96;--bs-gray-dark:#373a3c;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#868e96;--bs-gray-700:#495057;--bs-gray-800:#373a3c;--bs-gray-900:#212529;--bs-primary:#2780e3;--bs-secondary:#373a3c;--bs-success:#3fb618;--bs-info:#9954bb;--bs-warning:#ff7518;--bs-danger:#ff0039;--bs-light:#f8f9fa;--bs-dark:#373a3c;--bs-primary-rgb:39,128,227;--bs-secondary-rgb:55,58,60;--bs-success-rgb:63,182,24;--bs-info-rgb:153,84,187;--bs-warning-rgb:255,117,24;--bs-danger-rgb:255,0,57;--bs-light-rgb:248,249,250;--bs-dark-rgb:55,58,60;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:55,58,60;--bs-body-bg-rgb:255,255,255;--bs-font-sans-serif:"Source Sans Pro",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#373a3c;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:400;line-height:1.2}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#2780e3;text-decoration:underline}a:hover{color:#1f66b6}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#868e96;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-botLine truncated
+143
View File
@@ -0,0 +1,143 @@
// Cyborg 5.1.3
// Bootswatch
// Variables
$web-font-path: "https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" !default;
@if $web-font-path {
@import url($web-font-path);
}
// Navbar
.navbar {
&.bg-primary {
border: 1px solid $gray-700;
}
&.bg-dark {
background-color: $body-bg !important;
border: 1px solid $gray-700;
}
&.bg-light {
background-color: $gray-500 !important;
}
&.fixed-top {
border-width: 0 0 1px;
}
&.fixed-bottom {
border-width: 1px 0 0;
}
}
// Buttons
.btn {
@each $color, $value in $theme-colors {
&-#{$color} {
@if $enable-gradients {
background: $value linear-gradient(180deg, mix($white, $value, 15%), $value) repeat-x;
} @else {
background-color: $value;
}
}
}
}
// Forms
legend {
color: $white;
}
.form-control {
background-clip: border-box;
&:disabled,
&[readonly] {
border-color: transparent;
}
}
// Navs
.nav-tabs,
.nav-pills {
.nav-link {
color: $white;
&:hover {
background-color: $gray-700;
}
&.disabled,
&.disabled:hover {
background-color: transparent;
color: $nav-link-disabled-color;
}
&.active {
background-color: $primary;
}
}
}
.breadcrumb {
a {
color: $white;
}
}
.pagination {
a:hover {
text-decoration: none;
}
}
// Indicators
.alert {
border: none;
color: $white;
a,
.alert-link {
color: $white;
text-decoration: underline;
}
@each $color, $value in $theme-colors {
&-#{$color} {
@if $enable-gradients {
background: $value linear-gradient(180deg, mix($white, $value, 15%), $value) repeat-x;
} @else {
background-color: $value;
}
}
}
}
.badge {
&.bg-dark {
color: $gray-900;
}
}
// Containers
.list-group-item-action {
&:hover {
border-color: $primary;
}
}
.popover {
&-title {
border-bottom: none;
}
}
+183
View File
@@ -0,0 +1,183 @@
// Cyborg 5.1.3
// Bootswatch
@use "sass:color";
$theme: "cyborg" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #e9ecef !default;
$gray-300: #dee2e6 !default;
$gray-400: #adafae !default;
$gray-500: #888 !default;
$gray-600: #555 !default;
$gray-700: #282828 !default;
$gray-800: #222 !default;
$gray-900: #212529 !default;
$black: #000 !default;
$blue: #2a9fd6 !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #c00 !default;
$orange: #fd7e14 !default;
$yellow: #f80 !default;
$green: #77b300 !default;
$teal: #20c997 !default;
$cyan: #93c !default;
$primary: $blue !default;
$secondary: $gray-600 !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-800 !default;
$dark: $gray-400 !default;
$min-contrast-ratio: 2.25 !default;
// Body
$body-bg: #060606 !default;
$body-color: $gray-400 !default;
// Fonts
// stylelint-disable-next-line value-keyword-case
$font-family-sans-serif: Roboto, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif !default;
$h1-font-size: 4rem !default;
$h2-font-size: 3rem !default;
$h3-font-size: 2.5rem !default;
$h4-font-size: 2rem !default;
$h5-font-size: 1.5rem !default;
$headings-color: $white !default;
// Tables
$table-color: $white !default;
$table-accent-bg: rgba($white, .05) !default;
$table-hover-bg: rgba($white, .075) !default;
$table-border-color: $gray-700 !default;
$table-dark-bg: $gray-500 !default;
$table-dark-border-color: color.adjust($gray-500, $lightness: -7.5%) !default;
$table-bg-scale: 0 !default;
// Buttons
$input-btn-padding-x: 1rem !default;
// Forms
$input-bg: $white !default;
$input-disabled-bg: $gray-400 !default;
$input-color: $gray-900 !default;
$input-border-color: $white !default;
$input-border-width: 0 !default;
$input-group-addon-color: $white !default;
$input-group-addon-bg: $gray-700 !default;
$input-group-addon-border-color: transparent !default;
$form-check-input-bg: $white !default;
$form-check-input-border: none !default;
$form-file-button-color: $white !default;
// Dropdowns
$dropdown-bg: $gray-700 !default;
$dropdown-divider-bg: $gray-800 !default;
$dropdown-link-color: $white !default;
$dropdown-link-hover-color: $white !default;
$dropdown-link-hover-bg: $primary !default;
// Navs
$nav-tabs-border-color: $table-border-color !default;
$nav-tabs-link-hover-border-color: $nav-tabs-border-color !default;
$nav-tabs-link-active-color: $white !default;
$nav-tabs-link-active-bg: $nav-tabs-border-color !default;
$nav-tabs-link-active-border-color: $nav-tabs-border-color !default;
// Navbar
$navbar-dark-hover-color: $white !default;
// Pagination
$pagination-color: $white !default;
$pagination-bg: $gray-700 !default;
$pagination-border-color: transparent !default;
$pagination-hover-color: $white !default;
$pagination-hover-bg: $primary !default;
$pagination-hover-border-color: $pagination-border-color !default;
$pagination-disabled-bg: $pagination-bg !default;
$pagination-disabled-border-color: $pagination-border-color !default;
// Cards
$card-bg: $gray-700 !default;
// Tooltips
$tooltip-bg: $gray-700 !default;
$tooltip-opacity: 1 !default;
// Popovers
$popover-bg: $gray-700 !default;
// Toasts
$toast-color: $white !default;
$toast-background-color: $gray-800 !default;
$toast-border-color: $gray-700 !default;
$toast-header-color: $body-color !default;
$toast-header-background-color: $toast-background-color !default;
$toast-header-border-color: $toast-border-color !default;
// Modals
$modal-content-bg: $gray-800 !default;
$modal-header-border-color: $gray-700 !default;
// Progress bars
$progress-bg: $gray-700 !default;
// List group
$list-group-color: $white !default;
$list-group-bg: $gray-800 !default;
$list-group-border-color: $gray-700 !default;
$list-group-hover-bg: $primary !default;
$list-group-disabled-bg: $gray-700 !default;
$list-group-action-color: $white !default;
$list-group-action-active-bg: $primary !default;
// Breadcrumbs
$breadcrumb-padding-y: .375rem !default;
$breadcrumb-padding-x: .75rem !default;
$breadcrumb-bg: $gray-700 !default;
$breadcrumb-border-radius: .25rem !default;
// Close
$btn-close-color: $white !default;
$btn-close-opacity: .6 !default;
$btn-close-hover-opacity: 1 !default;
// Code
$pre-color: inherit !default;
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
/*!
* Bootswatch v5.1.3
* Homepage: https://bootswatch.com
* Copyright 2012-2021 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/@import url(https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap);:root{--bs-blue:#2a9fd6;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#e83e8c;--bs-red:#c00;--bs-orange:#fd7e14;--bs-yellow:#f80;--bs-green:#77b300;--bs-teal:#20c997;--bs-cyan:#93c;--bs-white:#fff;--bs-gray:#555;--bs-gray-dark:#222;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#adafae;--bs-gray-500:#888;--bs-gray-600:#555;--bs-gray-700:#282828;--bs-gray-800:#222;--bs-gray-900:#212529;--bs-primary:#2a9fd6;--bs-secondary:#555;--bs-success:#77b300;--bs-info:#93c;--bs-warning:#f80;--bs-danger:#c00;--bs-light:#222;--bs-dark:#adafae;--bs-primary-rgb:42,159,214;--bs-secondary-rgb:85,85,85;--bs-success-rgb:119,179,0;--bs-info-rgb:153,51,204;--bs-warning-rgb:255,136,0;--bs-danger-rgb:204,0,0;--bs-light-rgb:34,34,34;--bs-dark-rgb:173,175,174;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:173,175,174;--bs-body-bg-rgb:6,6,6;--bs-font-sans-serif:Roboto,-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue",Arial,sans-serif;--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#adafae;--bs-body-bg:#060606}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:#fff}.h1,h1{font-size:calc(1.525rem + 3.3vw)}@media (min-width:1200px){.h1,h1{font-size:4rem}}.h2,h2{font-size:calc(1.425rem + 2.1vw)}@media (min-width:1200px){.h2,h2{font-size:3rem}}.h3,h3{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h3,h3{font-size:2.5rem}}.h4,h4{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h4,h4{font-size:2rem}}.h5,h5{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h5,h5{font-size:1.5rem}}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#2a9fd6;text-decoration:underline}a:hover{color:#227fab}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em;color:inherit}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#555;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:cLine truncated
+76
View File
@@ -0,0 +1,76 @@
// Darkly 5.1.3
// Bootswatch
// Variables
$web-font-path: "https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400&display=swap" !default;
@if $web-font-path {
@import url($web-font-path);
}
// Typography
.blockquote {
&-footer {
color: $gray-600;
}
}
// Forms
.input-group-addon {
color: $white;
}
.form-floating > label {
color: $gray-700;
}
// Navs
.nav-tabs,
.nav-pills {
.nav-link,
.nav-link.active,
.nav-link.active:focus,
.nav-link.active:hover,
.nav-item.open .nav-link,
.nav-item.open .nav-link:focus,
.nav-item.open .nav-link:hover {
color: $white;
}
}
.breadcrumb a {
color: $white;
}
.pagination {
a:hover {
text-decoration: none;
}
}
// Indicators
.alert {
border: none;
color: $white;
a,
.alert-link {
color: $white;
text-decoration: underline;
}
@each $color, $value in $theme-colors {
&-#{$color} {
@if $enable-gradients {
background: $value linear-gradient(180deg, mix($white, $value, 15%), $value) repeat-x;
} @else {
background-color: $value;
}
}
}
}
+175
View File
@@ -0,0 +1,175 @@
// Darkly 5.1.3
// Bootswatch
@use "sass:color";
$theme: "darkly" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #ebebeb !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: #adb5bd !default;
$gray-600: #888 !default;
$gray-700: #444 !default;
$gray-800: #303030 !default;
$gray-900: #222 !default;
$black: #000 !default;
$blue: #375a7f !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #e74c3c !default;
$orange: #fd7e14 !default;
$yellow: #f39c12 !default;
$green: #00bc8c !default;
$teal: #20c997 !default;
$cyan: #3498db !default;
$primary: $blue !default;
$secondary: $gray-700 !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-500 !default;
$dark: $gray-800 !default;
$min-contrast-ratio: 1.9 !default;
// Body
$body-bg: $gray-900 !default;
$body-color: $white !default;
// Links
$link-color: $success !default;
// Fonts
// stylelint-disable-next-line value-keyword-case
$font-family-sans-serif: Lato, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default;
$h1-font-size: 3rem !default;
$h2-font-size: 2.5rem !default;
$h3-font-size: 2rem !default;
$text-muted: $gray-600 !default;
// Tables
$table-border-color: $gray-700 !default;
$table-bg-scale: 0 !default;
// Forms
$input-bg: $white !default;
$input-color: $gray-800 !default;
$input-border-color: $body-bg !default;
$input-group-addon-color: $gray-500 !default;
$input-group-addon-bg: $gray-700 !default;
$form-check-input-bg: $white !default;
$form-check-input-border: none !default;
$form-file-button-color: $white !default;
// Dropdowns
$dropdown-bg: $gray-900 !default;
$dropdown-border-color: $gray-700 !default;
$dropdown-divider-bg: $gray-700 !default;
$dropdown-link-color: $white !default;
$dropdown-link-hover-color: $white !default;
$dropdown-link-hover-bg: $primary !default;
// Navs
$nav-link-padding-x: 2rem !default;
$nav-link-disabled-color: $gray-500 !default;
$nav-tabs-border-color: $gray-700 !default;
$nav-tabs-link-hover-border-color: $nav-tabs-border-color $nav-tabs-border-color transparent !default;
$nav-tabs-link-active-color: $white !default;
$nav-tabs-link-active-border-color: $nav-tabs-border-color $nav-tabs-border-color transparent !default;
// Navbar
$navbar-padding-y: 1rem !default;
$navbar-dark-color: rgba($white, .6) !default;
$navbar-dark-hover-color: $white !default;
$navbar-light-color: rgba($gray-900, .7) !default;
$navbar-light-hover-color: $gray-900 !default;
$navbar-light-active-color: $gray-900 !default;
$navbar-light-toggler-border-color: rgba($gray-900, .1) !default;
// Pagination
$pagination-color: $white !default;
$pagination-bg: $success !default;
$pagination-border-width: 0 !default;
$pagination-border-color: transparent !default;
$pagination-hover-color: $white !default;
$pagination-hover-bg: color.adjust($success, $lightness: 10%) !default;
$pagination-hover-border-color: transparent !default;
$pagination-active-bg: $pagination-hover-bg !default;
$pagination-active-border-color: transparent !default;
$pagination-disabled-color: $white !default;
$pagination-disabled-bg: color.adjust($success, $lightness: -15%) !default;
$pagination-disabled-border-color: transparent !default;
// Cards
$card-cap-bg: $gray-700 !default;
$card-bg: $gray-800 !default;
// Popovers
$popover-bg: $gray-800 !default;
$popover-header-bg: $gray-700 !default;
// Toasts
$toast-background-color: $gray-700 !default;
$toast-header-background-color: $gray-800 !default;
// Modals
$modal-content-bg: $gray-800 !default;
$modal-content-border-color: $gray-700 !default;
$modal-header-border-color: $gray-700 !default;
// Progress bars
$progress-bg: $gray-700 !default;
// List group
$list-group-color: $body-color !default;
$list-group-bg: $gray-800 !default;
$list-group-border-color: $gray-700 !default;
$list-group-hover-bg: $gray-700 !default;
$list-group-action-hover-color: $list-group-color !default;
$list-group-action-active-bg: $gray-900 !default;
// Breadcrumbs
$breadcrumb-padding-y: .375rem !default;
$breadcrumb-padding-x: .75rem !default;
$breadcrumb-bg: $gray-700 !default;
$breadcrumb-border-radius: .25rem !default;
// Close
$btn-close-color: $white !default;
$btn-close-opacity: .4 !default;
$btn-close-hover-opacity: 1 !default;
// Code
$pre-color: inherit !default;
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
/*!
* Bootswatch v5.1.3
* Homepage: https://bootswatch.com
* Copyright 2012-2021 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/@import url(https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400&display=swap);:root{--bs-blue:#375a7f;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#e83e8c;--bs-red:#e74c3c;--bs-orange:#fd7e14;--bs-yellow:#f39c12;--bs-green:#00bc8c;--bs-teal:#20c997;--bs-cyan:#3498db;--bs-white:#fff;--bs-gray:#888;--bs-gray-dark:#303030;--bs-gray-100:#f8f9fa;--bs-gray-200:#ebebeb;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#888;--bs-gray-700:#444;--bs-gray-800:#303030;--bs-gray-900:#222;--bs-primary:#375a7f;--bs-secondary:#444;--bs-success:#00bc8c;--bs-info:#3498db;--bs-warning:#f39c12;--bs-danger:#e74c3c;--bs-light:#adb5bd;--bs-dark:#303030;--bs-primary-rgb:55,90,127;--bs-secondary-rgb:68,68,68;--bs-success-rgb:0,188,140;--bs-info-rgb:52,152,219;--bs-warning-rgb:243,156,18;--bs-danger-rgb:231,76,60;--bs-light-rgb:173,181,189;--bs-dark-rgb:48,48,48;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:255,255,255;--bs-body-bg-rgb:34,34,34;--bs-font-sans-serif:Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#fff;--bs-body-bg:#222}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.425rem + 2.1vw)}@media (min-width:1200px){.h1,h1{font-size:3rem}}.h2,h2{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h2,h2{font-size:2.5rem}}.h3,h3{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h3,h3{font-size:2rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#00bc8c;text-decoration:underline}a:hover{color:#009670}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em;color:inherit}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#222;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#888;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottomLine truncated
+75
View File
@@ -0,0 +1,75 @@
// Exor 3.0.2 (Based on bootstrap 5.1.3)
// Variables
$web-font-path: "https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400&display=swap" !default;
@if $web-font-path {
@import url($web-font-path);
}
// Typography
.blockquote {
&-footer {
color: $gray-600;
}
}
// Forms
.input-group-addon {
color: $white;
}
.form-floating > label {
color: $gray-700;
}
// Navs
.nav-tabs,
.nav-pills {
.nav-link,
.nav-link.active,
.nav-link.active:focus,
.nav-link.active:hover,
.nav-item.open .nav-link,
.nav-item.open .nav-link:focus,
.nav-item.open .nav-link:hover {
color: $white;
}
}
.breadcrumb a {
color: $white;
}
.pagination {
a:hover {
text-decoration: none;
}
}
// Indicators
.alert {
border: none;
color: $white;
a,
.alert-link {
color: $white;
text-decoration: underline;
}
@each $color, $value in $theme-colors {
&-#{$color} {
@if $enable-gradients {
background: $value linear-gradient(180deg, mix($white, $value, 15%), $value) repeat-x;
} @else {
background-color: $value;
}
}
}
}
+176
View File
@@ -0,0 +1,176 @@
// Exor 3.0.2 (Based on bootstrap 5.1.3)
@use "sass:color";
$theme: "exor" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #ebebeb !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: #adb5bd !default;
$gray-600: #888 !default;
$gray-700: #444 !default;
$gray-800: #303030 !default;
$gray-900: #222 !default;
$dark-gray: #454545 !default;
$light-gray: #b5bcc4 !default;
$black: #000 !default;
$blue: #375a7f !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #e74c3c !default;
$orange: #fd7e14 !default;
$yellow: #f39c12 !default;
$green: #00bc8c !default;
$teal: #20c997 !default;
$cyan: #3498db !default;
$primary: #ffbd11 !default;
$secondary: $gray-700 !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-500 !default;
$dark: $gray-800 !default;
$min-contrast-ratio: 1.9 !default;
// Body
$body-bg: $gray-900 !default;
$body-color: $white !default;
// Links
$link-color: $success !default;
// Fonts
// stylelint-disable-next-line value-keyword-case
$font-family-sans-serif: Lato, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default;
$h1-font-size: 3rem !default;
$h2-font-size: 2.5rem !default;
$h3-font-size: 2rem !default;
$text-muted: $gray-600 !default;
// Tables
$table-border-color: $dark-gray !default;
$table-bg-scale: 0 !default;
// Forms
$input-bg: $white !default;
$input-color: $gray-800 !default;
$input-border-color: $body-bg !default;
$input-group-addon-color: $gray-500 !default;
$input-group-addon-bg: $gray-700 !default;
$form-check-input-bg: $white !default;
$form-check-input-border: none !default;
$form-file-button-color: $white !default;
// Dropdowns
$dropdown-bg: $gray-900 !default;
$dropdown-border-color: $gray-700 !default;
$dropdown-divider-bg: $gray-700 !default;
$dropdown-link-color: $white !default;
$dropdown-link-hover-color: $white !default;
$dropdown-link-hover-bg: $primary !default;
// Navs
$nav-link-padding-x: 2rem !default;
$nav-link-disabled-color: $gray-500 !default;
$nav-tabs-border-color: $gray-700 !default;
$nav-tabs-link-hover-border-color: $nav-tabs-border-color $nav-tabs-border-color transparent !default;
$nav-tabs-link-active-color: $white !default;
$nav-tabs-link-active-border-color: $nav-tabs-border-color $nav-tabs-border-color transparent !default;
// Navbar
$navbar-padding-y: 1rem !default;
$navbar-dark-color: rgba($white, .6) !default;
$navbar-dark-hover-color: $white !default;
$navbar-light-color: rgba($gray-900, .7) !default;
$navbar-light-hover-color: $gray-900 !default;
$navbar-light-active-color: $gray-900 !default;
$navbar-light-toggler-border-color: rgba($gray-900, .1) !default;
// Pagination
$pagination-color: $white !default;
$pagination-bg: $success !default;
$pagination-border-width: 0 !default;
$pagination-border-color: transparent !default;
$pagination-hover-color: $white !default;
$pagination-hover-bg: color.adjust($success, $lightness: 10%) !default;
$pagination-hover-border-color: transparent !default;
$pagination-active-bg: $pagination-hover-bg !default;
$pagination-active-border-color: transparent !default;
$pagination-disabled-color: $white !default;
$pagination-disabled-bg: color.adjust($success, $lightness: -15%) !default;
$pagination-disabled-border-color: transparent !default;
// Cards
$card-cap-bg: $gray-700 !default;
$card-bg: $gray-800 !default;
// Popovers
$popover-bg: $gray-800 !default;
$popover-header-bg: $gray-700 !default;
// Toasts
$toast-background-color: $gray-700 !default;
$toast-header-background-color: $gray-800 !default;
// Modals
$modal-content-bg: $gray-800 !default;
$modal-content-border-color: $gray-700 !default;
$modal-header-border-color: $gray-700 !default;
// Progress bars
$progress-bg: $gray-700 !default;
// List group
$list-group-color: $body-color !default;
$list-group-bg: $gray-800 !default;
$list-group-border-color: $gray-700 !default;
$list-group-hover-bg: $gray-700 !default;
$list-group-action-hover-color: $list-group-color !default;
$list-group-action-active-bg: $gray-900 !default;
// Breadcrumbs
$breadcrumb-padding-y: .375rem !default;
$breadcrumb-padding-x: .75rem !default;
$breadcrumb-bg: $gray-700 !default;
$breadcrumb-border-radius: .25rem !default;
// Close
$btn-close-color: $white !default;
$btn-close-opacity: .4 !default;
$btn-close-hover-opacity: 1 !default;
// Code
$pre-color: inherit !default;
File diff suppressed because it is too large. Load diff
+11
View File
@@ -0,0 +1,11 @@
/*!
* Exor 3.0.2
* Copyright 2020-2022 Joe Uhren
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/@import url(https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400&display=swap);:root{--bs-blue:#ffbd11;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#e83e8c;--bs-red:#e74c3c;--bs-orange:#fd7e14;--bs-yellow:#f39c12;--bs-green:#00bc8c;--bs-teal:#20c997;--bs-cyan:#3498db;--bs-white:#fff;--bs-gray:#888;--bs-gray-dark:#303030;--bs-gray-100:#f8f9fa;--bs-gray-200:#ebebeb;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#888;--bs-gray-700:#444;--bs-gray-800:#303030;--bs-gray-900:#222;--bs-primary:#ffbd11;--bs-secondary:#444;--bs-success:#00bc8c;--bs-info:#3498db;--bs-warning:#f39c12;--bs-danger:#e74c3c;--bs-light:#adb5bd;--bs-dark:#303030;--bs-primary-rgb:55,90,127;--bs-secondary-rgb:68,68,68;--bs-success-rgb:0,188,140;--bs-info-rgb:52,152,219;--bs-warning-rgb:243,156,18;--bs-danger-rgb:231,76,60;--bs-light-rgb:173,181,189;--bs-dark-rgb:48,48,48;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:255,255,255;--bs-body-bg-rgb:34,34,34;--bs-font-sans-serif:Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#fff;--bs-body-bg:#222}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.425rem + 2.1vw)}@media (min-width:1200px){.h1,h1{font-size:3rem}}.h2,h2{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h2,h2{font-size:2.5rem}}.h3,h3{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h3,h3{font-size:2rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#ffbd11;text-decoration:none;background-color:transparent}table a{color:#fff;text-decoration:none;background-color:transparent}a:hover{color:orange}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em;color:inherit}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#222;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#888;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{Line truncated
+86
View File
@@ -0,0 +1,86 @@
// Flatly 5.1.3
// Bootswatch
// Variables
$web-font-path: "https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400&display=swap" !default;
@if $web-font-path {
@import url($web-font-path);
}
// Navbar
.bg-primary {
.navbar-nav .show > .nav-link,
.navbar-nav .nav-link.active,
.navbar-nav .nav-link:hover,
.navbar-nav .nav-link:focus {
color: $success !important;
}
}
// Navs
.nav-tabs {
.nav-link.active,
.nav-link.active:focus,
.nav-link.active:hover,
.nav-item.open .nav-link,
.nav-item.open .nav-link:focus,
.nav-item.open .nav-link:hover {
color: $primary;
}
}
.pagination {
a:hover {
text-decoration: none;
}
}
// Indicators
.badge {
&.bg-light {
color: $dark;
}
}
.alert {
border: none;
color: $white;
a,
.alert-link {
color: $white;
text-decoration: underline;
}
@each $color, $value in $theme-colors {
&-#{$color} {
@if $enable-gradients {
background: $value linear-gradient(180deg, mix($body-bg, $value, 15%), $value) repeat-x;
} @else {
background-color: $value;
}
}
}
&-light {
&,
a,
.alert-link {
color: $body-color;
}
}
}
// Containers
.modal,
.toast {
.btn-close {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'><path d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/></svg>");
}
}
+115
View File
@@ -0,0 +1,115 @@
// Flatly 5.1.3
// Bootswatch
@use "sass:color";
$theme: "flatly" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #ecf0f1 !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: #b4bcc2 !default;
$gray-600: #95a5a6 !default;
$gray-700: #7b8a8b !default;
$gray-800: #343a40 !default;
$gray-900: #212529 !default;
$black: #000 !default;
$blue: #2c3e50 !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #e74c3c !default;
$orange: #fd7e14 !default;
$yellow: #f39c12 !default;
$green: #18bc9c !default;
$teal: #20c997 !default;
$cyan: #3498db !default;
$primary: $blue !default;
$secondary: $gray-600 !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-200 !default;
$dark: $gray-700 !default;
$min-contrast-ratio: 2.05 !default;
// Links
$link-color: $success !default;
// Fonts
// stylelint-disable-next-line value-keyword-case
$font-family-sans-serif: Lato, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default;
$h1-font-size: 3rem !default;
$h2-font-size: 2.5rem !default;
$h3-font-size: 2rem !default;
// Tables
$table-bg-scale: 0 !default;
// Dropdowns
$dropdown-link-color: $gray-700 !default;
$dropdown-link-hover-color: $white !default;
$dropdown-link-hover-bg: $primary !default;
// Navs
$nav-link-padding-y: .5rem !default;
$nav-link-padding-x: 2rem !default;
$nav-link-disabled-color: $gray-600 !default;
$nav-tabs-border-color: $gray-200 !default;
// Navbar
$navbar-padding-y: 1rem !default;
$navbar-dark-color: $white !default;
$navbar-dark-hover-color: $primary !default;
$navbar-dark-active-color: $primary !default;
$navbar-dark-brand-color: $white !default;
$navbar-dark-brand-hover-color: $navbar-dark-brand-color !default;
// Pagination
$pagination-color: $white !default;
$pagination-bg: $success !default;
$pagination-border-width: 0 !default;
$pagination-border-color: transparent !default;
$pagination-hover-color: $white !default;
$pagination-hover-bg: color.adjust($success, $lightness: -15%) !default;
$pagination-hover-border-color: transparent !default;
$pagination-active-bg: $pagination-hover-bg !default;
$pagination-active-border-color: transparent !default;
$pagination-disabled-color: $gray-200 !default;
$pagination-disabled-bg: color.adjust($success, $lightness: 15%) !default;
$pagination-disabled-border-color: transparent !default;
// List group
$list-group-hover-bg: $gray-200 !default;
$list-group-disabled-bg: $gray-200 !default;
// Breadcrumbs
$breadcrumb-padding-y: .375rem !default;
$breadcrumb-padding-x: .75rem !default;
$breadcrumb-border-radius: .25rem !default;
// Close
$btn-close-color: $white !default;
$btn-close-opacity: .4 !default;
$btn-close-hover-opacity: 1 !default;
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
/*!
* Bootswatch v5.1.3
* Homepage: https://bootswatch.com
* Copyright 2012-2021 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/@import url(https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400&display=swap);:root{--bs-blue:#2c3e50;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#e83e8c;--bs-red:#e74c3c;--bs-orange:#fd7e14;--bs-yellow:#f39c12;--bs-green:#18bc9c;--bs-teal:#20c997;--bs-cyan:#3498db;--bs-white:#fff;--bs-gray:#95a5a6;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#ecf0f1;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#b4bcc2;--bs-gray-600:#95a5a6;--bs-gray-700:#7b8a8b;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#2c3e50;--bs-secondary:#95a5a6;--bs-success:#18bc9c;--bs-info:#3498db;--bs-warning:#f39c12;--bs-danger:#e74c3c;--bs-light:#ecf0f1;--bs-dark:#7b8a8b;--bs-primary-rgb:44,62,80;--bs-secondary-rgb:149,165,166;--bs-success-rgb:24,188,156;--bs-info-rgb:52,152,219;--bs-warning-rgb:243,156,18;--bs-danger-rgb:231,76,60;--bs-light-rgb:236,240,241;--bs-dark-rgb:123,138,139;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:33,37,41;--bs-body-bg-rgb:255,255,255;--bs-font-sans-serif:Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.425rem + 2.1vw)}@media (min-width:1200px){.h1,h1{font-size:3rem}}.h2,h2{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h2,h2{font-size:2.5rem}}.h3,h3{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h3,h3{font-size:2rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#18bc9c;text-decoration:underline}a:hover{color:#13967d}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#95a5a6;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;paddingLine truncated
@@ -0,0 +1,63 @@
// Journal 5.1.3
// Bootswatch
// Variables
$web-font-path: "https://fonts.googleapis.com/css2?family=News+Cycle:wght@400;700&display=swap" !default;
@if $web-font-path {
@import url($web-font-path);
}
// Navbar
.bg-dark {
background-color: $black !important;
}
.bg-light {
background-color: $white !important;
color: $black;
border: 1px solid $gray-200;
&.navbar-fixed-top {
border-width: 0 0 1px;
}
&.navbar-fixed-bottom {
border-width: 1px 0 0;
}
}
.navbar {
font-size: 18px;
font-family: $headings-font-family;
font-weight: $headings-font-weight;
}
.navbar-brand {
padding-top: .5rem;
font-size: inherit;
font-weight: $headings-font-weight;
text-transform: uppercase;
}
// Buttons
.btn {
font-family: $headings-font-family;
font-weight: $headings-font-weight;
&-secondary,
&-warning {
color: $white;
}
}
// Navs
.pagination {
a:hover {
text-decoration: none;
}
}
+64
View File
@@ -0,0 +1,64 @@
// Journal 5.1.3
// Bootswatch
$theme: "journal" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #eee !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: #aaa !default;
$gray-600: #777 !default;
$gray-700: #495057 !default;
$gray-800: #333 !default;
$gray-900: #222 !default;
$black: #000 !default;
$blue: #eb6864 !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #f57a00 !default;
$orange: #fd7e14 !default;
$yellow: #f5e625 !default;
$green: #22b24c !default;
$teal: #20c997 !default;
$cyan: #369 !default;
$primary: $blue !default;
$secondary: $gray-500 !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-100 !default;
$dark: $gray-900 !default;
$min-contrast-ratio: 1.28 !default;
// Fonts
$headings-font-family: "News Cycle", "Arial Narrow Bold", sans-serif !default;
$headings-font-weight: 700 !default;
$headings-line-height: 1.1 !default;
// Buttons
$input-btn-padding-x: 1rem !default;
// Navbar
$navbar-light-color: rgba($black, .7) !default;
$navbar-light-hover-color: $black !default;
$navbar-light-active-color: $black !default;
// Pagination
$pagination-hover-color: $white !default;
$pagination-hover-bg: $primary !default;
$pagination-hover-border-color: $primary !default;
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
/*!
* Bootswatch v5.1.3
* Homepage: https://bootswatch.com
* Copyright 2012-2021 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/@import url(https://fonts.googleapis.com/css2?family=News+Cycle:wght@400;700&display=swap);:root{--bs-blue:#eb6864;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#e83e8c;--bs-red:#f57a00;--bs-orange:#fd7e14;--bs-yellow:#f5e625;--bs-green:#22b24c;--bs-teal:#20c997;--bs-cyan:#369;--bs-white:#fff;--bs-gray:#777;--bs-gray-dark:#333;--bs-gray-100:#f8f9fa;--bs-gray-200:#eee;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#aaa;--bs-gray-600:#777;--bs-gray-700:#495057;--bs-gray-800:#333;--bs-gray-900:#222;--bs-primary:#eb6864;--bs-secondary:#aaa;--bs-success:#22b24c;--bs-info:#369;--bs-warning:#f5e625;--bs-danger:#f57a00;--bs-light:#f8f9fa;--bs-dark:#222;--bs-primary-rgb:235,104,100;--bs-secondary-rgb:170,170,170;--bs-success-rgb:34,178,76;--bs-info-rgb:51,102,153;--bs-warning-rgb:245,230,37;--bs-danger-rgb:245,122,0;--bs-light-rgb:248,249,250;--bs-dark-rgb:34,34,34;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:34,34,34;--bs-body-bg-rgb:255,255,255;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#222;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-family:"News Cycle","Arial Narrow Bold",sans-serif;font-weight:700;line-height:1.1}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#eb6864;text-decoration:underline}a:hover{color:#bc5350}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#222;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#777;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;borderLine truncated
+112
View File
@@ -0,0 +1,112 @@
// Litera 5.1.3
// Bootswatch
// Navbar
.navbar {
font-size: $font-size-sm;
&.bg-dark {
background-color: $success !important;
}
&.bg-light {
background-color: $white !important;
border: 1px solid rgba(0, 0, 0, .1);
&.navbar-fixed-top {
border-width: 0 0 1px;
}
&.navbar-fixed-bottom {
border-width: 1px 0 0;
}
}
}
// Typography
p {
font-family: $font-family-serif;
}
blockquote {
font-style: italic;
}
footer {
font-size: $font-size-sm;
}
.lead {
color: $gray-600;
font-family: $font-family-sans-serif;
}
// Tables
table,
.table {
font-size: $font-size-sm;
}
// Navs
.nav,
.breadcrumb,
.pagination {
font-size: $font-size-sm;
}
.dropdown-menu {
font-size: $font-size-sm;
}
// Indicators
.alert {
color: $white;
font-size: $font-size-sm;
&,
p {
font-family: $font-family-sans-serif;
}
a,
.alert-link {
color: $white;
font-weight: 400;
text-decoration: underline;
}
@each $color, $value in $theme-colors {
&-#{$color} {
@if $enable-gradients {
background: $value linear-gradient($value, mix($body-bg, $value, 15%)) repeat-x;
} @else {
background-color: $value;
}
}
}
&-light {
&,
a,
.alert-link {
color: $body-color;
}
}
}
.badge {
&.bg-light {
color: $dark;
}
}
// Containers
.list-group {
font-size: $font-size-sm;
}
+100
View File
@@ -0,0 +1,100 @@
// Litera 5.1.3
// Bootswatch
$theme: "litera" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #e9ecef !default;
$gray-300: #ddd !default;
$gray-400: #ced4da !default;
$gray-500: #adb5bd !default;
$gray-600: #868e96 !default;
$gray-700: #495057 !default;
$gray-800: #343a40 !default;
$gray-900: #212529 !default;
$black: #000 !default;
$blue: #4582ec !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #d9534f !default;
$orange: #fd7e14 !default;
$yellow: #f0ad4e !default;
$green: #02b875 !default;
$teal: #20c997 !default;
$cyan: #17a2b8 !default;
$primary: $blue !default;
$secondary: $gray-500 !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-100 !default;
$dark: $gray-800 !default;
$min-contrast-ratio: 1.85 !default;
// Body
$body-color: $gray-800 !default;
// Fonts
// stylelint-disable value-keyword-case
$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default;
$font-family-serif: Georgia, Cambria, "Times New Roman", Times, serif !default;
// stylelint-enable
$font-size-base: 1.1rem !default;
$headings-font-weight: 700 !default;
// Tables
$table-border-color: rgba(0, 0, 0, .1) !default;
$table-bg-scale: 0 !default;
// Buttons
$input-btn-padding-y: .5rem !default;
$input-btn-padding-x: 1.1rem !default;
$btn-font-family: $font-family-sans-serif !default;
$btn-font-size: .875rem !default;
$btn-font-size-sm: .688rem !default;
$btn-border-radius: 1.078em !default;
$btn-border-radius-lg: 2.688em !default;
$btn-border-radius-sm: .844em !default;
// Forms
$input-border-color: rgba(0, 0, 0, .1) !default;
$input-group-addon-bg: $gray-200 !default;
// Navbar
$navbar-dark-color: rgba($white, .6) !default;
$navbar-dark-hover-color: $white !default;
$navbar-light-hover-color: $body-color !default;
$navbar-light-active-color: $body-color !default;
// Tooltips
$tooltip-font-size: 11px !default;
// Badges
$badge-font-weight: 400 !default;
$badge-padding-y: .6em !default;
$badge-padding-x: 1.2em !default;
// Alerts
$alert-border-width: 0 !default;
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
/*!
* Bootswatch v5.1.3
* Homepage: https://bootswatch.com
* Copyright 2012-2021 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/:root{--bs-blue:#4582ec;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#e83e8c;--bs-red:#d9534f;--bs-orange:#fd7e14;--bs-yellow:#f0ad4e;--bs-green:#02b875;--bs-teal:#20c997;--bs-cyan:#17a2b8;--bs-white:#fff;--bs-gray:#868e96;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#ddd;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#868e96;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#4582ec;--bs-secondary:#adb5bd;--bs-success:#02b875;--bs-info:#17a2b8;--bs-warning:#f0ad4e;--bs-danger:#d9534f;--bs-light:#f8f9fa;--bs-dark:#343a40;--bs-primary-rgb:69,130,236;--bs-secondary-rgb:173,181,189;--bs-success-rgb:2,184,117;--bs-info-rgb:23,162,184;--bs-warning-rgb:240,173,78;--bs-danger-rgb:217,83,79;--bs-light-rgb:248,249,250;--bs-dark-rgb:52,58,64;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:52,58,64;--bs-body-bg-rgb:255,255,255;--bs-font-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1.1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#343a40;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:700;line-height:1.2}.h1,h1{font-size:calc(1.4rem + 1.8vw)}@media (min-width:1200px){.h1,h1{font-size:2.75rem}}.h2,h2{font-size:calc(1.345rem + 1.14vw)}@media (min-width:1200px){.h2,h2{font-size:2.2rem}}.h3,h3{font-size:calc(1.3175rem + .81vw)}@media (min-width:1200px){.h3,h3{font-size:1.925rem}}.h4,h4{font-size:calc(1.29rem + .48vw)}@media (min-width:1200px){.h4,h4{font-size:1.65rem}}.h5,h5{font-size:calc(1.2625rem + .15vw)}@media (min-width:1200px){.h5,h5{font-size:1.375rem}}.h6,h6{font-size:1.1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#4582ec;text-decoration:underline}a:hover{color:#3768bd}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#868e96;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;paddLine truncated
+321
View File
@@ -0,0 +1,321 @@
// Lumen 5.1.3
// Bootswatch
// Variables
$web-font-path: "https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,300;0,400;0,700;1,400&display=swap" !default;
@if $web-font-path {
@import url($web-font-path);
}
// Mixins
@mixin shadow($width: 4px){
border-style: solid;
border-width: 0 1px $width 1px;
}
// Navbar
.navbar {
@include shadow();
@each $color, $value in $theme-colors {
&.bg-#{$color} {
border-color: shade-color($value, 10%);
}
}
}
// Buttons
.btn {
@include shadow();
text-transform: uppercase;
&:not(.disabled):hover {
margin-top: 1px;
border-bottom-width: 3px;
}
&:not(.disabled):active {
margin-top: 2px;
border-bottom-width: 2px;
@include box-shadow(none);
}
@each $color, $value in $theme-colors {
&-#{$color} {
&:hover,
&:active,
&:focus {
background-color: $value;
}
&,
&:not(.disabled):hover,
&:not(.disabled):active,
&:focus {
border-color: shade-color($value, 10%);
}
}
}
}
[class*="btn-outline"] {
border-top-width: 1px;
}
.btn-group-vertical {
.btn + .btn {
&:hover {
margin-top: -1px;
border-top-width: 1px;
}
&:active {
margin-top: -1px;
border-top-width: 2px;
}
}
}
// Typography
.text-secondary {
color: $gray-700 !important;
}
.blockquote-footer {
color: $gray-600;
}
// Forms
.form-control {
box-shadow: inset 0 2px 0 rgba(0, 0, 0, .075);
}
// Navs
.nav {
.open > a,
.open > a:hover,
.open > a:focus {
border-color: transparent;
}
}
.nav-tabs {
.nav-link {
color: $body-color;
&,
&.disabled,
&.disabled:hover,
&.disabled:focus {
margin-top: 6px;
border-color: $nav-tabs-border-color;
transition: padding-bottom .2s ease-in-out, margin-top .2s ease-in-out, border-bottom .2s ease-in-out;
}
&:not(.disabled):hover,
&:not(.disabled):focus,
&.active {
padding-bottom: add(.5rem, 6px);
border-bottom-color: transparent;
margin-top: 0;
}
}
&.nav-justified > li {
vertical-align: bottom;
}
}
.dropdown-menu {
margin-top: 0;
@include shadow();
border-top-width: 1px;
@include box-shadow(none);
}
.breadcrumb {
border-color: shade-color($breadcrumb-bg, 10%);
@include shadow();
}
.pagination {
> li > a,
> li > span {
position: relative;
top: 0;
@include shadow();
color: $pagination-color;
font-weight: 700;
text-transform: uppercase;
&:hover,
&:focus {
top: 1px;
border-bottom-width: 3px;
text-decoration: none;
}
&:active {
top: 2px;
border-bottom-width: 2px;
}
}
> .disabled > a,
> .disabled > span {
&:hover {
top: 0;
@include shadow();
}
&:active {
top: 0;
@include shadow();
}
}
}
.pager {
> li > a,
> li > span,
> .disabled > a,
> .disabled > span {
&,
&:hover,
&:active {
border-left-width: 2px;
border-right-width: 2px;
}
}
}
// Indicators
.btn-close {
text-decoration: none;
opacity: .4;
&:hover,
&:focus {
opacity: 1;
}
}
.alert {
color: $white;
@include shadow();
&-primary {
background-color: $primary;
border-color: shade-color($primary, 10%);
}
&-secondary {
background-color: $secondary;
border-color: shade-color($secondary, 10%);
}
&-success {
background-color: $success;
border-color: shade-color($success, 10%);
}
&-info {
background-color: $info;
border-color: shade-color($info, 10%);
}
&-danger {
background-color: $danger;
border-color: shade-color($danger, 10%);
}
&-warning {
background-color: $warning;
border-color: shade-color($warning, 10%);
}
&-dark {
background-color: $dark;
border-color: shade-color($dark, 10%);
}
&-light {
background-color: $light;
border-color: shade-color($light, 10%);
}
.alert-link {
font-weight: 400;
color: $white;
text-decoration: underline;
}
&-secondary,
&-light {
&,
a,
.alert-link {
color: $body-color;
}
}
}
.badge {
&.bg-secondary,
&.bg-light {
color: $dark;
}
}
// Containers
a.list-group-item {
&-success {
&.active {
background-color: $success;
}
&.active:hover,
&.active:focus {
background-color: shade-color($success, 10%);
}
}
&-warning {
&.active {
background-color: $warning;
}
&.active:hover,
&.active:focus {
background-color: shade-color($warning, 10%);
}
}
&-danger {
&.active {
background-color: $danger;
}
&.active:hover,
&.active:focus {
background-color: shade-color($danger, 10%);
}
}
}
.modal,
.toast {
.btn-close {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'><path d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/></svg>");
}
}
+95
View File
@@ -0,0 +1,95 @@
// Lumen 5.1.3
// Bootswatch
@use "sass:color";
$theme: "lumen" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f6f6f6 !default;
$gray-200: #f0f0f0 !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: #adb5bd !default;
$gray-600: #999 !default;
$gray-700: #555 !default;
$gray-800: #333 !default;
$gray-900: #222 !default;
$black: #000 !default;
$blue: #158cba !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #ff4136 !default;
$orange: #fd7e14 !default;
$yellow: #ff851b !default;
$green: #28b62c !default;
$teal: #20c997 !default;
$cyan: #75caeb !default;
$primary: $blue !default;
$secondary: $gray-200 !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-100 !default;
$dark: $gray-700 !default;
$min-contrast-ratio: 1.75 !default;
// Fonts
// stylelint-disable-next-line value-keyword-case
$font-family-sans-serif: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default;
// Tables
$table-bg-scale: 0 !default;
// Buttons
$btn-font-weight: 700 !default;
// Dropdowns
$dropdown-link-color: rgba(0, 0, 0, .5) !default;
// Navs
$nav-tabs-border-color: $gray-200 !default;
$nav-tabs-link-hover-border-color: $nav-tabs-border-color !default;
$nav-tabs-link-active-color: $gray-900 !default;
$nav-tabs-link-active-border-color: $nav-tabs-border-color !default;
// Pagination
$pagination-color: $gray-700 !default;
$pagination-bg: $gray-200 !default;
$pagination-hover-color: $pagination-color !default;
$pagination-hover-bg: $pagination-bg !default;
$pagination-active-border-color: color.adjust($primary, $lightness: -5%) !default;
$pagination-disabled-color: $gray-600 !default;
$pagination-disabled-bg: $pagination-bg !default;
// Breadcrumbs
$breadcrumb-padding-y: .375rem !default;
$breadcrumb-padding-x: .75rem !default;
$breadcrumb-bg: $pagination-bg !default;
$breadcrumb-border-radius: .25rem !default;
// Modals
$modal-content-border-color: rgba($black, .1) !default;
// Close
$btn-close-color: $white !default;
$btn-close-opacity: .4 !default;
$btn-close-hover-opacity: 1 !default;
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
/*!
* Bootswatch v5.1.3
* Homepage: https://bootswatch.com
* Copyright 2012-2021 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/@import url(https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,300;0,400;0,700;1,400&display=swap);:root{--bs-blue:#158cba;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#e83e8c;--bs-red:#ff4136;--bs-orange:#fd7e14;--bs-yellow:#ff851b;--bs-green:#28b62c;--bs-teal:#20c997;--bs-cyan:#75caeb;--bs-white:#fff;--bs-gray:#999;--bs-gray-dark:#333;--bs-gray-100:#f6f6f6;--bs-gray-200:#f0f0f0;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#999;--bs-gray-700:#555;--bs-gray-800:#333;--bs-gray-900:#222;--bs-primary:#158cba;--bs-secondary:#f0f0f0;--bs-success:#28b62c;--bs-info:#75caeb;--bs-warning:#ff851b;--bs-danger:#ff4136;--bs-light:#f6f6f6;--bs-dark:#555;--bs-primary-rgb:21,140,186;--bs-secondary-rgb:240,240,240;--bs-success-rgb:40,182,44;--bs-info-rgb:117,202,235;--bs-warning-rgb:255,133,27;--bs-danger-rgb:255,65,54;--bs-light-rgb:246,246,246;--bs-dark-rgb:85,85,85;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:34,34,34;--bs-body-bg-rgb:255,255,255;--bs-font-sans-serif:"Source Sans Pro",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#222;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#158cba;text-decoration:underline}a:hover{color:#117095}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#222;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#999;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:Line truncated
+184
View File
@@ -0,0 +1,184 @@
// Lux 5.1.3
// Bootswatch
// Variables
$web-font-path: "https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@400;600&display=swap" !default;
@if $web-font-path {
@import url($web-font-path);
}
// Navbar
.navbar {
font-size: $font-size-sm;
text-transform: uppercase;
font-weight: 600;
&-nav {
.nav-link {
padding-top: .715rem;
padding-bottom: .715rem;
}
}
&-brand {
margin-right: 2rem;
}
}
.bg-primary {
background-color: theme-color("primary") !important;
}
.bg-light {
border: 1px solid rgba(0, 0, 0, .1);
&.navbar-fixed-top {
border-width: 0 0 1px;
}
&.navbar-bottom-top {
border-width: 1px 0 0;
}
}
.nav-item {
margin-right: 2rem;
}
// Buttons
.btn {
font-size: $font-size-sm;
text-transform: uppercase;
&-sm {
font-size: 10px;
}
&-warning {
&,
&:hover,
&:not([disabled]):not(.disabled):active,
&:focus {
color: $white;
}
}
}
.btn-outline-secondary {
border-color: $gray-600;
color: $gray-600;
&:not([disabled]):not(.disabled):hover,
&:not([disabled]):not(.disabled):focus,
&:not([disabled]):not(.disabled):active {
background-color: $gray-400;
border-color: $gray-400;
color: $white;
}
&:not([disabled]):not(.disabled):focus {
box-shadow: 0 0 0 .2rem rgba($gray-400, .5);
}
}
[class*="btn-outline-"] {
border-width: 2px;
}
.border-secondary {
border: 1px solid $gray-400 !important;
}
// Typography
body {
font-weight: 200;
letter-spacing: 1px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
text-transform: uppercase;
letter-spacing: 3px;
}
.text-secondary {
color: $body-color !important;
}
// Tables
th {
font-size: $font-size-sm;
text-transform: uppercase;
}
.table {
th,
td {
padding: 1.5rem;
}
&-sm {
th,
td {
padding: .75rem;
}
}
}
// Navs
.dropdown-menu {
font-size: $font-size-sm;
text-transform: none;
}
// Indicators
.badge {
padding-top: .28rem;
&-pill {
border-radius: 10rem;
}
&.bg-secondary,
&.bg-light {
color: $dark;
}
}
// Containers
.list-group-item {
h1,
h2,
h3,
h4,
h5,
h6,
.h1,
.h2,
.h3,
.h4,
.h5,
.h6 {
color: inherit;
}
}
.card {
&-title,
&-header {
color: inherit;
}
}
+103
View File
@@ -0,0 +1,103 @@
// Lux 5.1.3
// Bootswatch
$theme: "lux" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #f7f7f9 !default;
$gray-300: #eceeef !default;
$gray-400: #ced4da !default;
$gray-500: #adb5bd !default;
$gray-600: #919aa1 !default;
$gray-700: #55595c !default;
$gray-800: #343a40 !default;
$gray-900: #1a1a1a !default;
$black: #000 !default;
$blue: #007bff !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #d9534f !default;
$orange: #fd7e14 !default;
$yellow: #f0ad4e !default;
$green: #4bbf73 !default;
$teal: #20c997 !default;
$cyan: #1f9bcf !default;
$primary: $gray-900 !default;
$secondary: $white !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $white !default;
$dark: $gray-800 !default;
$min-contrast-ratio: 2.3 !default;
// Options
$enable-rounded: false !default;
// Body
$body-color: $gray-700 !default;
// Fonts
// stylelint-disable-next-line value-keyword-case
$font-family-sans-serif: "Nunito Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default;
$h1-font-size: 2rem !default;
$h2-font-size: 1.75rem !default;
$h3-font-size: 1.5rem !default;
$h4-font-size: 1.25rem !default;
$h5-font-size: 1rem !default;
$h6-font-size: .75rem !default;
$headings-font-weight: 600 !default;
$headings-color: $gray-900 !default;
// Tables
$table-border-color: rgba(0, 0, 0, .05) !default;
// Buttons + Forms
$input-btn-border-width: 0 !default;
// Buttons
$btn-line-height: 1.5rem !default;
$input-btn-padding-y: .75rem !default;
$input-btn-padding-x: 1.5rem !default;
$input-btn-padding-y-sm: .5rem !default;
$input-btn-padding-x-sm: 1rem !default;
$input-btn-padding-y-lg: 2rem !default;
$input-btn-padding-x-lg: 2rem !default;
$btn-font-weight: 600 !default;
// Forms
$input-line-height: 1.5 !default;
$input-bg: $gray-200 !default;
$input-disabled-bg: $gray-300 !default;
$input-group-addon-bg: $gray-300 !default;
// Navbar
$navbar-padding-y: 1.5rem !default;
$navbar-dark-hover-color: $white !default;
$navbar-light-color: rgba($black, .3) !default;
$navbar-light-hover-color: $gray-900 !default;
$navbar-light-active-color: $gray-900 !default;
// Pagination
$pagination-border-color: transparent !default;
$pagination-hover-border-color: $pagination-border-color !default;
$pagination-disabled-border-color: $pagination-border-color !default;
+11226
View File
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
/*!
* Bootswatch v5.1.3
* Homepage: https://bootswatch.com
* Copyright 2012-2021 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/@import url(https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@400;600&display=swap);:root{--bs-blue:#007bff;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#e83e8c;--bs-red:#d9534f;--bs-orange:#fd7e14;--bs-yellow:#f0ad4e;--bs-green:#4bbf73;--bs-teal:#20c997;--bs-cyan:#1f9bcf;--bs-white:#fff;--bs-gray:#919aa1;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#f7f7f9;--bs-gray-300:#eceeef;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#919aa1;--bs-gray-700:#55595c;--bs-gray-800:#343a40;--bs-gray-900:#1a1a1a;--bs-primary:#1a1a1a;--bs-secondary:#fff;--bs-success:#4bbf73;--bs-info:#1f9bcf;--bs-warning:#f0ad4e;--bs-danger:#d9534f;--bs-light:#fff;--bs-dark:#343a40;--bs-primary-rgb:26,26,26;--bs-secondary-rgb:255,255,255;--bs-success-rgb:75,191,115;--bs-info-rgb:31,155,207;--bs-warning-rgb:240,173,78;--bs-danger-rgb:217,83,79;--bs-light-rgb:255,255,255;--bs-dark-rgb:52,58,64;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:85,89,92;--bs-body-bg-rgb:255,255,255;--bs-font-sans-serif:"Nunito Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#55595c;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:600;line-height:1.2;color:#1a1a1a}.h1,h1{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h1,h1{font-size:2rem}}.h2,h2{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h2,h2{font-size:1.75rem}}.h3,h3{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h3,h3{font-size:1.5rem}}.h4,h4{font-size:1.25rem}.h5,h5{font-size:1rem}.h6,h6{font-size:.75rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#1a1a1a;text-decoration:underline}a:hover{color:#151515}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#1a1a1a}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#919aa1;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@mediaLine truncated
+654
View File
@@ -0,0 +1,654 @@
// Materia 5.1.3
// Bootswatch
// Variables
$web-font-path: "https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" !default;
@if $web-font-path {
@import url($web-font-path);
}
// Mixins
@mixin ripple($color) {
position: relative;
&::before {
content: "";
display: block;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
margin-left: 0;
@include gradient-radial($color 10%, transparent 10.01%);
background-size: 1000% 1000%;
background-position: 50%;
border: none;
opacity: 0;
pointer-events: none;
transition: background .5s, opacity 1s;
}
&:active::before {
background-size: 0 0;
opacity: .2;
transition: none;
}
&.disabled,
&[disabled] {
&::before {
display: none;
}
}
}
@mixin btn($class,$bg,$color) {
.btn-#{$class} {
&:focus {
background-color: $bg;
box-shadow: 0 0 0 2px rgba(204, 204, 204, .5);
}
&:hover,
&:active:hover {
background-color: shade-color($bg, 12%);
}
&:active {
box-shadow: 2px 2px 4px rgba(0, 0, 0, .4);
}
@include ripple($color);
}
.btn-outline-#{$class} {
@include ripple($color);
}
}
.dropdown-toggle::after,
.dropup .dropdown-toggle::after,
.dropstart .dropdown-toggle::after,
.dropend .dropdown-toggle::after {
border-width: 4px;
}
// Navbar
.navbar {
border: none;
box-shadow: 0 1px 2px rgba(0, 0, 0, .3);
&-brand {
font-size: 24px;
}
&-nav .nav-link {
padding-top: .9rem;
padding-bottom: .9rem;
}
&.bg-dark,
&.bg-primary {
input[type="search"],
input[type="text"],
input[type="password"],
input[type="email"],
input[type="number"],
input[type="tel"] {
color: $white;
box-shadow: inset 0 -1px 0 rgba(255, 255, 255, .5);
&:focus {
box-shadow: inset 0 -2px 0 $white;
}
&::placeholder {
color: rgba(255, 255, 255, .5);
}
}
}
}
// Buttons
@include btn(primary, $primary, $white);
@include btn(secondary, $secondary, $gray-500);
@include btn(success, $success, $white);
@include btn(info, $info, $white);
@include btn(warning, $warning, $white);
@include btn(danger, $danger, $white);
@include btn(dark, $dark, $white);
@include btn(light, $light, $white);
.btn {
text-transform: uppercase;
border: none;
box-shadow: 0 1px 4px rgba(0, 0, 0, .4);
transition: color .4s, background-color .4s, border-color .4s, box-shadow .4s;
&-link {
box-shadow: none;
color: $link-color;
&:hover,
&:focus {
box-shadow: none;
color: $link-hover-color;
text-decoration: $link-hover-decoration;
}
&.disabled, // Although btn-link is intended for buttons, which want to look like link, I include here a.disable for the sake of consistency
&[disabled],
fieldset[disabled] & {
&:hover,
&:active:hover {
color: $btn-link-disabled-color;
text-decoration: none;
}
}
}
&-secondary {
&.disabled,
&[disabled],
fieldset[disabled] & {
background-color: rgba(0, 0, 0, .1);
color: rgba(0, 0, 0, .4);
opacity: 1;
&:hover,
&:focus {
background-color: rgba(0, 0, 0, .1);
}
}
}
&-outline-secondary {
border-color: $gray-200;
color: $gray-300;
}
&-warning {
color: $white;
}
}
.btn-group {
.btn + .btn,
.btn + .btn-group,
.btn-group + .btn,
.btn-group + .btn-group {
margin-left: 0;
}
&-vertical {
> .btn + .btn,
> .btn + .btn-group,
> .btn-group + .btn,
> .btn-group + .btn-group {
margin-top: 0;
}
}
.btn + .btn,
.btn + .btn-group > .dropdown-toggle {
box-shadow: 1px 1px 4px rgba(0, 0, 0, .4);
}
}
.border-secondary {
border: 1px solid #dfdfdf !important;
}
// Typography
body,
input,
button {
letter-spacing: .1px;
}
p {
margin: 0 0 1em;
}
.text-secondary {
color: $gray-500 !important;
}
// Tables
.table-hover {
> tbody > tr,
> tbody > tr > th,
> tbody > tr > td {
transition: background-color .2s, color .2s;
}
}
.thead-inverse th {
background-color: $primary;
color: $white;
}
// Forms
.col-form-label {
font-size: 16px;
&-sm {
font-size: $font-size-sm;
}
&-lg {
font-size: $font-size-lg;
}
}
textarea,
textarea.form-control,
input.form-control,
input[type="text"],
input[type="password"],
input[type="email"],
input[type="number"],
[type="text"].form-control,
[type="password"].form-control,
[type="email"].form-control,
[type="tel"].form-control,
[contenteditable].form-control {
box-shadow: inset 0 -1px 0 #ddd;
transition: box-shadow .2s;
&:focus {
box-shadow: inset 0 -2px 0 $primary;
}
&[disabled],
&[readonly] {
box-shadow: none;
border-bottom: 1px dotted #ddd;
}
&[disabled],
&[disabled]::placeholder {
color: #ddd;
}
&::-ms-clear {
display: none;
}
}
select,
select.form-control {
appearance: none;
padding: .5rem 0;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='4' viewBox='0 0 8 4'%3e%3cpolygon fill='%23666' points='8 0 4 4 0 0'/%3e%3c/svg%3e%0a");
background-size: 8px 4px;
background-repeat: no-repeat;
background-position: right center;
box-shadow: inset 0 -1px 0 #ddd;
&::-ms-expand {
display: none;
}
&.input {
&-sm {
font-size: $font-size-sm;
}
&-lg {
font-size: $font-size-lg;
}
}
&:focus {
box-shadow: inset 0 -2px 0 $primary;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='4' viewBox='0 0 8 4'%3e%3cpolygon fill='%23212121' points='8 0 4 4 0 0'/%3e%3c/svg%3e%0a");
}
&[multiple] {
background: none;
}
}
.form-check-input {
width: 1.25em;
height: 1.25em;
margin-top: 1px;
border: 2px solid $gray-400;
&:checked[type="radio"] {
background-size: 1.8em;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%232196f3' stroke='%23fff' stroke-width='1' /%3e%3c/svg%3e"), var(--bs-gradient);
}
}
.form-check.form-switch {
.form-check-input {
position: relative;
height: .8em;
border: none;
background-image: none;
background-color: $gray-400;
&:focus {
box-shadow: none;
}
&::before {
content: "";
position: absolute;
top: -.2em;
left: -.2em;
width: 1.2em;
height: 1.2em;
background-color: $white;
border-radius: 50%;
box-shadow: 0 1px 4px rgba(0, 0, 0, .3);
transition: left .15s ease-in-out;
}
&::after {
content: "";
position: absolute;
top: -.2em;
left: -.2em;
width: 1.2em;
height: 1.2em;
border-radius: 50%;
box-shadow: 0 0 0 9px rgba(0, 0, 0, .05);
transform: scale(0);
transition: left .15s ease-in-out, transform .15s ease-in-out, box-shadow .15s ease-in-out;
z-index: -1;
}
&:hover:not(.disabled),
&:focus:not(.disabled) {
&::after {
transform: scale(.9);
}
}
&:focus:not(.disabled) {
&::after {
box-shadow: 0 0 0 9px rgba(0, 0, 0, .1);
}
}
&:checked {
background-color: rgba(33, 150, 243, .3);
&::before {
background-color: rgba(33, 150, 243, 1);
left: calc(100% - .8em);
}
&::after {
left: calc(100% - .8em);
box-shadow: 0 0 0 9px rgba(33, 150, 243, .1);
}
&:hover:not(.disabled),
&:focus:not(.disabled) {
&::after {
transform: scale(.9);
}
}
&:focus:not(.disabled) {
&::after {
box-shadow: 0 0 0 9px rgba(33, 150, 243, .2);
}
}
}
}
}
.form-check:not(.form-switch) {
.form-check-input {
&:checked[type="checkbox"] {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-width='2' d='M6 10l3 3l6-6'/%3e%3c/svg%3e"), var(--bs-gradient);
background-size: 1.6em;
}
}
}
.has-warning {
input:not([type="checkbox"]),
.form-control,
input.form-control[readonly],
input[type="text"][readonly],
[type="text"].form-control[readonly],
input:not([type="checkbox"]):focus,
.form-control:focus {
border-bottom: none;
box-shadow: inset 0 -2px 0 $warning;
}
}
.has-danger {
input:not([type="checkbox"]),
.form-control,
input.form-control[readonly],
input[type="text"][readonly],
[type="text"].form-control[readonly],
input:not([type="checkbox"]):focus,
.form-control:focus {
border-bottom: none;
box-shadow: inset 0 -2px 0 $danger;
}
}
.has-success {
input:not([type="checkbox"]),
.form-control,
input.form-control[readonly],
input[type="text"][readonly],
[type="text"].form-control[readonly],
input:not([type="checkbox"]):focus,
.form-control:focus {
border-bottom: none;
box-shadow: inset 0 -2px 0 $success;
}
}
// Remove the Bootstrap feedback styles for input addons
.input-group-addon {
.has-warning &,
.has-danger &,
.has-success & {
color: $input-color;
border-color: $input-group-addon-border-color;
background-color: $input-group-addon-bg;
}
}
.form-group-lg {
select,
select.form-control {
line-height: 1.5;
}
}
// Navs
.nav-tabs {
.nav-item + .nav-item {
margin-left: 0;
}
.nav-link,
.nav-link:focus {
margin-right: 0;
background-color: transparent;
border: none;
color: $body-color;
box-shadow: inset 0 -1px 0 #ddd;
transition: color .2s, box-shadow .2s;
&:hover {
background-color: transparent;
box-shadow: inset 0 -2px 0 $primary;
color: $primary;
}
}
.nav-link.active,
.nav-link.active:focus {
border: none;
box-shadow: inset 0 -2px 0 $primary;
color: $primary;
&:hover {
border: none;
color: $primary;
}
}
.nav-link.disabled {
box-shadow: inset 0 -1px 0 #ddd;
}
&.nav-justified {
.nav-link,
.nav-link:hover,
.nav-link:focus,
.nav-link.active,
.nav-link.active:hover,
.nav-link.active:focus {
border: none;
}
}
.dropdown-menu {
margin-top: 0;
}
}
.dropdown-menu {
margin-top: 0;
border: none;
box-shadow: 0 1px 4px rgba(0, 0, 0, .3);
}
// Indicators
.alert {
padding-right: 2.5rem;
border: none;
&,
h1,
h2,
h3,
h4,
h5,
h6 {
color: $white;
}
@each $color, $value in $theme-colors {
&-#{$color} {
@if $enable-gradients {
background: $value linear-gradient(180deg, mix($body-bg, $value, 15%), $value) repeat-x;
} @else {
background-color: $value;
}
}
}
a:not(.btn),
.alert-link {
color: $white;
font-weight: 700;
}
&-secondary,
&-light {
&,
a:not(.btn),
.alert-link {
color: $body-color;
}
}
}
.badge {
&.bg-secondary,
&.bg-light {
color: $dark;
}
}
.tag {
padding: 4px 6px;
}
// Containers
.card {
box-shadow: 0 1px 4px rgba(0, 0, 0, .4);
&.border-primary,
&.border-secondary,
&.border-success,
&.border-info,
&.border-warning,
&.border-danger,
&.border-light,
&.border-dark {
border-width: 1px;
}
}
.list-group {
&-item-action.active {
h1,
h2,
h3,
h4,
h5,
h6 {
color: $white;
}
}
}
.modal-content {
border-radius: .2rem;
box-shadow: 0 6px 36px rgba(0, 0, 0, .3);
}
.modal,
.toast {
.btn-close {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'><path d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/></svg>");
}
}
.popover {
border: none;
box-shadow: 0 1px 4px rgba(0, 0, 0, .3);
}
.carousel {
&-caption {
h1,
h2,
h3,
h4,
h5,
h6 {
color: inherit;
}
}
}
+114
View File
@@ -0,0 +1,114 @@
// Materia 5.1.3
// Bootswatch
$theme: "materia" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #eee !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: #bbb !default;
$gray-600: #666 !default;
$gray-700: #444 !default;
$gray-800: #222 !default;
$gray-900: #212121 !default;
$black: #000 !default;
$blue: #2196f3 !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #e51c23 !default;
$orange: #fd7e14 !default;
$yellow: #ff9800 !default;
$green: #4caf50 !default;
$teal: #20c997 !default;
$cyan: #9c27b0 !default;
$primary: $blue !default;
$secondary: $white !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-100 !default;
$dark: $gray-800 !default;
$min-contrast-ratio: 2.15 !default;
$enable-gradients: true !default;
// Body
$body-color: $gray-700 !default;
// Fonts
// stylelint-disable-next-line value-keyword-case
$font-family-sans-serif: Roboto, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif !default;
$font-size-base: 1rem !default;
$font-weight-base: 400 !default;
// Buttons
$input-btn-padding-y: .8rem !default;
$input-btn-padding-x: 1rem !default;
// Forms
$input-padding-y: 1rem !default;
$input-padding-x: 0 !default;
$input-padding-y-sm: 0 !default;
$input-padding-x-sm: 0 !default;
$input-padding-y-lg: ($font-size-base * 1.25) !default;
$input-padding-x-lg: 0 !default;
$input-bg: transparent !default;
$input-disabled-bg: transparent !default;
$input-color: $gray-600 !default;
$input-border-color: transparent !default;
$input-border-width: 0 !default;
$input-border-radius: 0 !default;
$input-border-radius-lg: 0 !default;
$input-border-radius-sm: 0 !default;
$input-placeholder-color: rgba(0, 0, 0, .4) !default;
$input-group-addon-bg: transparent !default;
// Navs
$nav-link-disabled-color: $gray-500 !default;
$nav-tabs-border-color: transparent !default;
// Navbar
$navbar-padding-y: 1rem !default;
$navbar-dark-color: rgba($white, .75) !default;
$navbar-dark-hover-color: $white !default;
// Cards
$card-border-width: 0 !default;
$card-border-color: transparent !default;
// Tooltips
$tooltip-bg: $gray-700 !default;
// Modals
$modal-content-border-color: transparent !default;
// Progress bars
$progress-height: .375rem !default;
$progress-border-radius: 0 !default;
// Close
$btn-close-color: $white !default;
$btn-close-opacity: .6 !default;
$btn-close-hover-opacity: 1 !default;
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
/*!
* Bootswatch v5.1.3
* Homepage: https://bootswatch.com
* Copyright 2012-2021 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/@import url(https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap);:root{--bs-blue:#2196f3;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#e83e8c;--bs-red:#e51c23;--bs-orange:#fd7e14;--bs-yellow:#ff9800;--bs-green:#4caf50;--bs-teal:#20c997;--bs-cyan:#9c27b0;--bs-white:#fff;--bs-gray:#666;--bs-gray-dark:#222;--bs-gray-100:#f8f9fa;--bs-gray-200:#eee;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#bbb;--bs-gray-600:#666;--bs-gray-700:#444;--bs-gray-800:#222;--bs-gray-900:#212121;--bs-primary:#2196f3;--bs-secondary:#fff;--bs-success:#4caf50;--bs-info:#9c27b0;--bs-warning:#ff9800;--bs-danger:#e51c23;--bs-light:#f8f9fa;--bs-dark:#222;--bs-primary-rgb:33,150,243;--bs-secondary-rgb:255,255,255;--bs-success-rgb:76,175,80;--bs-info-rgb:156,39,176;--bs-warning-rgb:255,152,0;--bs-danger-rgb:229,28,35;--bs-light-rgb:248,249,250;--bs-dark-rgb:34,34,34;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:68,68,68;--bs-body-bg-rgb:255,255,255;--bs-font-sans-serif:Roboto,-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue",Arial,sans-serif;--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#444;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#2196f3;text-decoration:underline}a:hover{color:#1a78c2}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212121;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#666;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){Line truncated
+144
View File
@@ -0,0 +1,144 @@
// Minty 5.1.3
// Bootswatch
// Variables
$web-font-path: "https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;700&display=swap" !default;
@if $web-font-path {
@import url($web-font-path);
}
// Navbar
.navbar {
font-family: $headings-font-family;
}
.bg-dark {
background-color: $secondary !important;
}
.border-dark {
border-color: $secondary !important;
}
// Buttons
.btn {
font-family: $headings-font-family;
&,
&:hover {
color: $white;
}
&-light,
&-light:hover {
color: $gray-700;
}
&-link,
&-link:hover {
color: $primary;
}
&-link.disabled:hover {
color: $gray-600;
}
&-outline-primary {
color: $primary;
}
&-outline-secondary {
color: $secondary;
}
&-outline-success {
color: $success;
}
&-outline-info {
color: $info;
}
&-outline-warning {
color: $warning;
}
&-outline-danger {
color: $danger;
}
&-outline-dark {
color: $dark;
}
&-outline-light {
color: $light;
}
}
// Forms
legend {
font-family: $headings-font-family;
}
// Navs
.dropdown-menu {
font-family: $font-family-sans-serif;
}
.breadcrumb {
a {
color: $navbar-dark-color;
}
a:hover {
color: $white;
text-decoration: none;
}
}
// Indicators
.alert {
a,
.alert-link {
color: $white;
}
&-light {
&,
a:not(.btn),
.alert-link {
color: $body-color;
}
}
}
.badge {
color: $white;
&.bg-light {
color: $gray-700;
}
}
// Containers
.card,
.list-group-item {
h1,
h2,
h3,
h4,
h5,
h6 {
color: inherit;
}
}
+106
View File
@@ -0,0 +1,106 @@
// Minty 5.1.3
// Bootswatch
$theme: "minty" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #f7f7f9 !default;
$gray-300: #eceeef !default;
$gray-400: #ced4da !default;
$gray-500: #aaa !default;
$gray-600: #888 !default;
$gray-700: #5a5a5a !default;
$gray-800: #343a40 !default;
$gray-900: #212529 !default;
$black: #000 !default;
$blue: #007bff !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #ff7851 !default;
$orange: #fd7e14 !default;
$yellow: #ffce67 !default;
$green: #56cc9d !default;
$teal: #20c997 !default;
$cyan: #6cc3d5 !default;
$primary: #78c2ad !default;
$secondary: #f3969a !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-100 !default;
$dark: $gray-800 !default;
$min-contrast-ratio: 1.45 !default;
// Body
$body-color: $gray-600 !default;
// Components
$border-radius: .4rem !default;
$border-radius-lg: .6rem !default;
$border-radius-sm: .3rem !default;
// Fonts
// stylelint-disable-next-line value-keyword-case
$headings-font-family: Montserrat, -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !default;
$headings-color: $gray-700 !default;
// Tables
$table-border-color: rgba(0, 0, 0, .05) !default;
$table-bg-scale: 0 !default;
// Dropdowns
$dropdown-link-hover-color: $white !default;
$dropdown-link-hover-bg: $secondary !default;
// Navbar
$navbar-dark-color: rgba($white, .6) !default;
$navbar-dark-hover-color: $white !default;
$navbar-light-color: rgba($black, .3) !default;
$navbar-light-hover-color: $gray-700 !default;
$navbar-light-active-color: $gray-700 !default;
$navbar-light-disabled-color: rgba($black, .1) !default;
// Pagination
$pagination-color: $white !default;
$pagination-bg: $primary !default;
$pagination-border-color: $primary !default;
$pagination-hover-color: $white !default;
$pagination-hover-bg: $secondary !default;
$pagination-hover-border-color: $pagination-hover-bg !default;
$pagination-active-bg: $secondary !default;
$pagination-active-border-color: $pagination-active-bg !default;
$pagination-disabled-color: $white !default;
$pagination-disabled-bg: #cce8e0 !default;
$pagination-disabled-border-color: $pagination-disabled-bg !default;
// Alerts
$alert-color-scale: 0% !default;
$alert-bg-scale: 0 !default;
// Breadcrumbs
$breadcrumb-padding-y: .375rem !default;
$breadcrumb-padding-x: .75rem !default;
$breadcrumb-bg: $primary !default;
$breadcrumb-divider-color: $white !default;
$breadcrumb-active-color: $breadcrumb-divider-color !default;
$breadcrumb-border-radius: .25rem !default;
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
/*!
* Bootswatch v5.1.3
* Homepage: https://bootswatch.com
* Copyright 2012-2021 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/@import url(https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;700&display=swap);:root{--bs-blue:#007bff;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#e83e8c;--bs-red:#ff7851;--bs-orange:#fd7e14;--bs-yellow:#ffce67;--bs-green:#56cc9d;--bs-teal:#20c997;--bs-cyan:#6cc3d5;--bs-white:#fff;--bs-gray:#888;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#f7f7f9;--bs-gray-300:#eceeef;--bs-gray-400:#ced4da;--bs-gray-500:#aaa;--bs-gray-600:#888;--bs-gray-700:#5a5a5a;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#78c2ad;--bs-secondary:#f3969a;--bs-success:#56cc9d;--bs-info:#6cc3d5;--bs-warning:#ffce67;--bs-danger:#ff7851;--bs-light:#f8f9fa;--bs-dark:#343a40;--bs-primary-rgb:120,194,173;--bs-secondary-rgb:243,150,154;--bs-success-rgb:86,204,157;--bs-info-rgb:108,195,213;--bs-warning-rgb:255,206,103;--bs-danger-rgb:255,120,81;--bs-light-rgb:248,249,250;--bs-dark-rgb:52,58,64;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:136,136,136;--bs-body-bg-rgb:255,255,255;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#888;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-family:Montserrat,-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:500;line-height:1.2;color:#5a5a5a}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#78c2ad;text-decoration:underline}a:hover{color:#609b8a}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.3rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#888;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-mLine truncated
+458
View File
@@ -0,0 +1,458 @@
// Morph 5.1.3
// Bootswatch
// Variables
$web-font-path: "https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap" !default;
@if $web-font-path {
@import url($web-font-path);
}
$btn-box-shadow-inset: inset 2px 3px 6px rgba($black, .2), inset -3px -2px 6px rgba($white, .2) !default;
@mixin shadow($shadow: $box-shadow) {
background-color: $gray-200;
border: none;
box-shadow: $shadow;
transition: background-color .15s ease-in-out, border .15s ease-in-out, box-shadow .15s ease-in-out, color .15s ease-in-out;
}
@mixin shadow-outline($shadow: $box-shadow) {
content: "";
position: absolute;
left: -.5rem;
right: -.5rem;
top: -.5rem;
bottom: -.5rem;
background-color: $body-bg;
border: 1px solid rgba($white, .1);
box-shadow: $shadow;
transition: background-color .15s ease-in-out, border .15s ease-in-out, box-shadow .15s ease-in-out, color .15s ease-in-out;
z-index: -1;
}
// Buttons
.btn {
position: relative;
color: $gray-700;
border-radius: $btn-border-radius;
@include shadow();
&:focus {
color: $gray-700;
}
&:hover,
&:focus,
&:active,
&:active:focus {
@include shadow();
color: $gray-700;
}
&:active,
&:active:focus {
border-color: transparent;
box-shadow: $btn-box-shadow-inset;
}
@each $color, $value in $theme-colors {
&-#{$color} {
&:active,
&:active:focus {
@if ($color == secondary or $color == light) {
background-color: $gray-200;
color: $gray-700;
} @else {
background-color: $value;
color: $white;
}
}
}
}
&-link {
font-weight: $btn-font-weight;
&:hover,
&:active,
&:active:focus {
color: $dark;
}
}
&.disabled {
background-color: $gray-200;
box-shadow: 2px 2px 5px rgba($black, .1), -2px -2px 5px rgba($white, .5);
color: $gray-700;
}
}
.btn-outline {
@each $color, $value in $theme-colors {
&-#{$color} {
background-color: $value;
box-shadow: 5px 5px 10px rgba($black, .2), -5px -5px 10px rgba($white, .1);
border: none;
@if ($color == secondary or $color == light) {
color: $gray-700;
} @else {
color: $white;
}
&:hover,
&:focus {
background-color: $value;
border: none;
box-shadow: 5px 5px 10px rgba($black, .2), -5px -5px 10px rgba($white, .1);
@if ($color == secondary or $color == light) {
color: $gray-700;
} @else {
color: $white;
}
}
&:active,
&:active:focus {
background-color: $value;
border: none;
box-shadow: inset 2px 3px 6px rgba($black, .1), inset -3px -2px 6px rgba($white, .1);
@if ($color == secondary or $color == light) {
color: $gray-700;
} @else {
color: $white;
}
}
}
}
}
.btn-group,
.btn-group-vertical {
@include shadow();
border-radius: $btn-border-radius;
border: none;
.btn,
.btn-group {
margin: 0;
box-shadow: none;
border: none;
&:hover,
&:active,
&:focus,
&:active:focus {
border: none;
}
}
}
.btn-group {
> .btn:nth-child(n + 3),
> :not(.btn-check) + .btn,
> .btn-group:not(:first-child) > .btn {
border-left: 1px solid $border-color;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
&:hover,
&:active,
&:active:focus {
border-left: 1px solid $border-color;
}
}
> .btn:not(:last-child):not(.dropdown-toggle),
> .btn-group:not(:last-child) > .btn {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
.btn-group-vertical {
border-radius: 1rem;
.btn {
border-radius: 1rem;
&:hover,
&:active,
&:focus,
&:active:focus {
border-radius: 1rem;
}
}
> .btn:nth-child(n + 3),
> :not(.btn-check) + .btn,
> .btn-group:not(:first-child) > .btn {
border-top-left-radius: 0;
border-top-right-radius: 0;
border-top: 1px solid rgba($black, .05);
&:hover,
&:active,
&:active:focus {
border-top-left-radius: 0;
border-top-right-radius: 0;
border-top: 1px solid rgba($black, .05);
}
}
> .btn:not(:last-child):not(.dropdown-toggle),
> .btn-group:not(:last-child) > .btn {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
&:hover,
&:active,
&:active:focus {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
}
}
.btn-check:checked + .btn,
.btn-check:active + .btn {
box-shadow: inset 2px 3px 6px rgba($black, .2);
@each $color, $value in $theme-colors {
&-#{$color} {
background-color: $value;
.btn-check:checked + &,
.btn-check:active + & {
@if $color == secondary {
color: $gray-700;
} @else {
color: $value;
}
}
}
}
}
.btn-check:not(:checked) + .btn,
.btn-check:not(:checked) + .btn:active {
background-color: $gray-200;
color: $gray-700;
}
.btn-check:checked ~ .btn-check:active + .btn,
.btn-check:checked ~ .btn-check:checked + .btn {
box-shadow: inset 0 3px 6px rgba($black, .2);
}
// Navs
.dropdown-menu {
backdrop-filter: blur(3px);
}
.nav-tabs {
@include shadow();
border-radius: $border-radius;
.nav-item {
box-shadow: 1px 0 $border-color;
&:first-child .nav-link {
border-top-left-radius: $border-radius;
border-bottom-left-radius: $border-radius;
}
&:last-child .nav-link {
border-top-right-radius: $border-radius;
border-bottom-right-radius: $border-radius;
}
}
.nav-link.active,
.nav-item.show .nav-link {
box-shadow: inset 0 3px 6px rgba($black, .2);
}
}
.nav-pills {
@include shadow();
padding: 1rem;
border-radius: $border-radius;
.nav-link.active {
box-shadow: inset 0 3px 6px rgba($black, .2);
}
}
.breadcrumb {
@include shadow();
border-radius: $border-radius;
}
.pagination {
@include shadow();
justify-content: center;
border-radius: $border-radius;
}
// Forms
.input-group {
background-color: $gray-100;
border-radius: $border-radius;
box-shadow: $box-shadow-inset;
> .form-control {
background: none;
padding-left: 0;
padding-right: 0;
box-shadow: none;
}
.input-group-text {
background: none;
}
}
.form-range {
&::-webkit-slider-runnable-track {
box-shadow: inset 1px 1px 4px rgba($black, .15);
}
&::-webkit-slider-thumb,
&:focus::-webkit-slider-thumb {
box-shadow: 1px 1px 3px rgba($black, .2), inset 2px 2px 8px rgba(shade-color($form-range-thumb-bg, 50%), .1);
}
}
.form-check-input {
background-color: $gray-400;
border: none;
box-shadow: inset 1px 1px 7px rgba($black, .2);
&:focus {
border: none;
box-shadow: none;
}
&:active {
filter: none;
}
&:checked {
background-color: $primary;
box-shadow: inset 1px 1px 7px rgba($black, .2);
}
}
.form-control {
&::-webkit-file-upload-button {
box-shadow: 2px 2px 5px rgba($black, .2), inset 3px 3px 10px rgba(shade-color($form-range-thumb-bg, 50%), .1);
}
}
.form-select:not([multiple]) {
position: relative;
box-shadow: $box-shadow;
}
// Indicators
.alert {
box-shadow: $dropdown-box-shadow;
backdrop-filter: blur(3px);
@each $color, $value in $theme-colors {
&-#{$color} {
background-color: rgba($value, .75);
box-shadow: $box-shadow-lg, inset 1px 1px 3px rgba(tint-color($value, 80%), .4), inset -5px -5px 20px rgba(shade-color($value, 80%), .05);
}
}
}
.badge {
&.bg-secondary,
&.bg-light {
color: $gray-700;
}
}
.tooltip {
&.show {
opacity: 1;
}
&-inner,
.arrow {
box-shadow: $dropdown-box-shadow;
backdrop-filter: blur(3px);
}
}
.popover,
.toast,
.modal-content {
box-shadow: $dropdown-box-shadow;
backdrop-filter: blur(3px);
}
.progress {
box-shadow: inset 2px 4px 6px rgba(shade-color($body-bg, 50%), .2), inset -3px -2px 5px rgba($white, .8);
}
.progress-bar {
box-shadow: 2px 2px 5px rgba($black, .2);
&:first-child {
border-top-left-radius: $border-radius-pill;
border-bottom-left-radius: $border-radius-pill;
}
&:last-child {
border-top-right-radius: $border-radius-pill;
border-bottom-right-radius: $border-radius-pill;
}
}
// Containers
.card {
box-shadow: inset 2px 2px 6px rgba(shade-color($body-bg, 50%), .2), inset -3px -2px 4px rgba($white, .2);
@each $color, $value in $theme-colors {
&-#{$color} {
box-shadow: inset 2px 2px 6px rgba(shade-color($value, 80%), .05), inset -3px -2px 4px rgba(tint-color($value, 80%), .2);
}
}
&-header {
border-bottom: 1px solid $border-color;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: inherit;
}
}
.list-group {
background-color: $card-bg;
box-shadow: inset 2px 2px 6px rgba(shade-color($body-bg, 50%), .2), inset -3px -2px 4px rgba($white, .2);
}
.list-group-item {
background-color: transparent;
}
+230
View File
@@ -0,0 +1,230 @@
// Morph 5.1.3
// Bootswatch
@use "sass:color";
$theme: "morph" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #f0f5fa !default;
$gray-200: #d9e3f1 !default;
$gray-300: #dee2e6 !default;
$gray-400: #bed1e6 !default;
$gray-500: #adb5bd !default;
$gray-600: #7f8a99 !default;
$gray-700: #7b8ab8 !default;
$gray-800: #444b40 !default;
$gray-900: #212529 !default;
$black: #000 !default;
$blue: #378dfc !default;
$indigo: #6610f2 !default;
$purple: #5b62f4 !default;
$pink: #d63384 !default;
$red: #e52527 !default;
$orange: #fd7e14 !default;
$yellow: #ffc107 !default;
$green: #43cc29 !default;
$teal: #20c997 !default;
$cyan: #0dcaf0 !default;
$primary: $blue !default;
$secondary: $gray-200 !default;
$success: $green !default;
$info: $purple !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-100 !default;
$dark: $gray-900 !default;
$min-contrast-ratio: 1.5 !default;
$enable-shadows: true !default;
// Body
$body-bg: $gray-200 !default;
$body-color: $gray-700 !default;
// Links
$link-color: color.adjust($body-color, $lightness: -20%) !default;
// Components
$border-width: 0 !default;
$border-color: rgba(color.adjust($body-bg, $lightness: -50%), .1) !default;
$border-radius-pill: 50rem !default;
$box-shadow: 5px 5px 10px rgba(color.adjust($body-bg, $lightness: -50%), .2), -5px -5px 10px rgba($white, .4) !default;
$box-shadow-sm: 0 .125rem .25rem rgba(color.adjust($body-bg, $lightness: -50%), .2) !default;
$box-shadow-lg: 8px 8px 40px rgba(color.adjust($body-bg, $lightness: -90%), .15) !default;
$box-shadow-inset: inset 2px 2px 8px rgba(color.adjust($body-bg, $lightness: -50%), .3), inset -3px -2px 5px rgba($white, .8) !default;
// Fonts
// stylelint-disable-next-line value-keyword-case
$font-family-sans-serif: Nunito, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default;
$headings-color: $link-color !default;
$text-muted: color.adjust($body-color, $lightness: 15%) !default;
// Buttons + Forms
$input-btn-padding-y: 1rem !default;
$input-btn-padding-x: 1.5rem !default;
// Buttons
$btn-font-weight: 600 !default;
$btn-padding-y-lg: 1.5rem !default;
$btn-padding-x-lg: 2.25rem !default;
$btn-box-shadow: $box-shadow !default;
$btn-border-radius: $border-radius-pill !default;
$btn-border-radius-sm: $border-radius-pill !default;
$btn-border-radius-lg: $border-radius-pill !default;
// Forms
$form-label-font-weight: $btn-font-weight !default;
$input-bg: $gray-100 !default;
$input-placeholder-color: $text-muted !default;
$form-switch-color: $white !default;
$form-switch-focus-color: $form-switch-color !default;
$form-select-indicator-color: $body-color !default;
$form-select-box-shadow: $box-shadow-inset !default;
$form-range-track-bg: rgba(color.adjust($body-bg, $lightness: -50%), .15) !default;
$form-range-thumb-bg: $gray-100 !default;
$form-range-thumb-active-bg: $form-range-thumb-bg !default;
$form-range-thumb-disabled-bg: $gray-200 !default;
$form-file-button-bg: $gray-100 !default;
// Navs
$nav-link-color: $body-color !default;
$nav-link-hover-color: $nav-link-color !default;
$nav-link-disabled-color: $text-muted !default;
$nav-tabs-border-radius: 0 !default;
$nav-tabs-link-active-color: $white !default;
$nav-tabs-link-active-bg: $primary !default;
// Navbar
$navbar-dark-color: rgba($white, .75) !default;
$navbar-dark-hover-color: $white !default;
$navbar-dark-active-color: $navbar-dark-hover-color !default;
$navbar-dark-disabled-color: rgba($white, .25) !default;
$navbar-light-color: $body-color !default;
$navbar-light-hover-color: $link-color !default;
$navbar-light-active-color: $navbar-light-hover-color !default;
$navbar-light-disabled-color: $text-muted !default;
// Dropdowns
$dropdown-bg: rgba($gray-100, .8) !default;
$dropdown-border-color: transparent !default;
$dropdown-box-shadow: $box-shadow-lg, inset 1px 1px 3px rgba($white, .5), inset -5px -5px 20px rgba($black, .05) !default;
$dropdown-link-color: $gray-700 !default;
$dropdown-link-hover-color: $gray-800 !default;
$dropdown-link-hover-bg: transparent !default;
// Pagination
$pagination-padding-y: 1rem !default;
$pagination-padding-x: .75rem !default;
$pagination-padding-y-sm: .5rem !default;
$pagination-padding-y-lg: 1.5rem !default;
$pagination-color: $gray-700 !default;
$pagination-bg: $body-bg !default;
$pagination-active-color: color.adjust($pagination-color, $lightness: -20%) !default;
$pagination-active-bg: transparent !default;
$pagination-disabled-color: $text-muted !default;
$pagination-disabled-bg: $pagination-bg !default;
// Cards
$card-spacer-y: 1.5rem !default;
$card-spacer-x: 1.5rem !default;
$card-cap-bg: transparent !default;
$card-bg: color.adjust($body-bg, $lightness: 3%) !default;
// Tooltips
$tooltip-color: $body-color !default;
$tooltip-bg: $dropdown-bg !default;
// Popovers
$popover-bg: $dropdown-bg !default;
$popover-header-bg: transparent !default;
// Toasts
$toast-background-color: $dropdown-bg !default;
$toast-border-width: 0 !default;
$toast-header-color: $body-color !default;
$toast-header-background-color: transparent !default;
// Badges
$badge-padding-y: .75em !default;
$badge-padding-x: 1.25em !default;
// Modals
$modal-content-bg: $dropdown-bg !default;
// Progress bars
$progress-height: 1.5rem !default;
$progress-border-radius: $border-radius-pill !default;
// List groups
$list-group-bg: $card-bg !default;
$list-group-hover-bg: transparent !default;
$list-group-active-color: $link-color !default;
$list-group-active-bg: transparent !default;
$list-group-disabled-color: $text-muted !default;
$list-group-disabled-bg: transparent !default;
$list-group-action-active-color: $link-color !default;
$list-group-action-active-bg: transparent !default;
// Breadcrumbs
$breadcrumb-padding-y: $pagination-padding-y !default;
$breadcrumb-padding-x: $pagination-padding-x !default;
$breadcrumb-divider-color: $text-muted !default;
$breadcrumb-active-color: $link-color !default;
// Close
$btn-close-color: $headings-color !default;
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
/*!
* Bootswatch v5.1.3
* Homepage: https://bootswatch.com
* Copyright 2012-2021 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/@import url(https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap);:root{--bs-blue:#378dfc;--bs-indigo:#6610f2;--bs-purple:#5b62f4;--bs-pink:#d63384;--bs-red:#e52527;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#43cc29;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#7f8a99;--bs-gray-dark:#444b40;--bs-gray-100:#f0f5fa;--bs-gray-200:#d9e3f1;--bs-gray-300:#dee2e6;--bs-gray-400:#bed1e6;--bs-gray-500:#adb5bd;--bs-gray-600:#7f8a99;--bs-gray-700:#7b8ab8;--bs-gray-800:#444b40;--bs-gray-900:#212529;--bs-primary:#378dfc;--bs-secondary:#d9e3f1;--bs-success:#43cc29;--bs-info:#5b62f4;--bs-warning:#ffc107;--bs-danger:#e52527;--bs-light:#f0f5fa;--bs-dark:#212529;--bs-primary-rgb:55,141,252;--bs-secondary-rgb:217,227,241;--bs-success-rgb:67,204,41;--bs-info-rgb:91,98,244;--bs-warning-rgb:255,193,7;--bs-danger-rgb:229,37,39;--bs-light-rgb:240,245,250;--bs-dark-rgb:33,37,41;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:123,138,184;--bs-body-bg-rgb:217,227,241;--bs-font-sans-serif:Nunito,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#7b8ab8;--bs-body-bg:#d9e3f1}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:0}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:#485785}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#485785;text-decoration:underline}a:hover{color:#39456b}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#adb6d3;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;Line truncated
+142
View File
@@ -0,0 +1,142 @@
// Pulse 5.1.3
// Bootswatch
// Buttons
.btn {
&:focus,
&:active,
&:active:focus,
&.active:focus {
outline: none;
}
&-secondary {
background-color: $white;
border-color: #ccc;
color: $gray-900;
&:hover {
background-color: $gray-300;
border-color: $gray-500;
color: $gray-900;
}
&.disabled {
background-color: $white;
border-color: tint-color(#ccc, 5%);
color: tint-color($gray-900, 5%);
}
}
&-warning {
color: $white;
}
&-primary:focus {
box-shadow: 0 0 5px tint-color($primary, 10%);
}
&-secondary:focus {
box-shadow: 0 0 5px $gray-400;
}
&-success:focus {
box-shadow: 0 0 5px tint-color($success, 10%);
}
&-info:focus {
box-shadow: 0 0 5px tint-color($info, 10%);
}
&-warning:focus {
box-shadow: 0 0 5px tint-color($warning, 10%);
}
&-danger:focus {
box-shadow: 0 0 5px tint-color($danger, 10%);
}
&.disabled:focus {
box-shadow: none;
}
}
// Tables
.table .thead-dark th {
background-color: $secondary;
border-color: $table-border-color;
}
// Forms
.form-control:focus {
box-shadow: 0 0 5px rgba(100, 65, 164, .4);
}
// Navs
.nav-tabs {
.nav-link,
.nav-link.active, {
border-width: 0 0 1px;
}
.nav-link:hover,
.nav-link.active,
.nav-link.active:hover,
.nav-link.active:focus {
border-bottom: 1px solid $primary;
}
.nav-item + .nav-item {
margin-left: 0;
}
}
.breadcrumb {
&-item.active {
color: $gray-700;
}
}
// Indicators
.badge {
&.bg-light {
color: $dark;
}
}
// Progress bars
.progress {
height: 8px;
}
// Containers
.list-group {
&-item {
color: rgba(255, 255, 255, .8);
&.active,
&:hover,
&:focus {
color: $white;
}
&.active {
font-weight: 700;
&:hover {
background-color: $list-group-hover-bg;
}
}
&.disabled:hover {
color: $list-group-disabled-color;
}
}
}
+98
View File
@@ -0,0 +1,98 @@
// Pulse 5.1.3
// Bootswatch
@use "sass:color";
$theme: "pulse" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #fafafa !default;
$gray-200: #f9f8fc !default;
$gray-300: #ededed !default;
$gray-400: #cbc8d0 !default;
$gray-500: #adb5bd !default;
$gray-600: #868e96 !default;
$gray-700: #444 !default;
$gray-800: #343a40 !default;
$gray-900: #17141f !default;
$black: #000 !default;
$blue: #007bff !default;
$indigo: #6610f2 !default;
$purple: #593196 !default;
$pink: #e83e8c !default;
$red: #fc3939 !default;
$orange: #fd7e14 !default;
$yellow: #efa31d !default;
$green: #13b955 !default;
$teal: #20c997 !default;
$cyan: #009cdc !default;
$primary: $purple !default;
$secondary: #a991d4 !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-200 !default;
$dark: $gray-900 !default;
$min-contrast-ratio: 2.1 !default;
// Options
$enable-rounded: false !default;
// Body
$body-color: $gray-700 !default;
// Links
$link-hover-color: $primary !default;
// Tables
$table-border-color: rgba(0, 0, 0, .05) !default;
// Forms
$input-focus-border-color: $primary !default;
// Dropdowns
$dropdown-link-color: $gray-700 !default;
$dropdown-link-hover-color: $white !default;
$dropdown-link-hover-bg: $primary !default;
// Navs
$nav-tabs-border-color: $gray-300 !default;
$nav-tabs-link-hover-border-color: $primary !default;
// Navbar
$navbar-padding-y: 1.2rem !default;
$navbar-dark-hover-color: rgba($white, .9) !default;
$navbar-dark-active-color: rgba($white, .9) !default;
$navbar-light-color: rgba($black, .4) !default;
$navbar-light-active-color: rgba($black, .7) !default;
$navbar-light-disabled-color: rgba($black, .2) !default;
// Progress bars
$progress-bg: $gray-300 !default;
$progress-bar-bg: $primary !default;
// List group
$list-group-bg: $gray-900 !default;
$list-group-border-color: transparent !default;
$list-group-hover-bg: color.adjust($list-group-bg, $lightness: 10%) !default;
$list-group-active-color: $white !default;
$list-group-active-bg: $list-group-bg !default;
$list-group-disabled-color: color.adjust($list-group-bg, $lightness: 30%) !default;
Loaded 100 of 198 files, more files were not shown because too many files have changed in this diff. Show more