new site
81
website/404/index.html
Normal file
@@ -0,0 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-P53NSV9J65"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-P53NSV9J65');
|
||||
</script>
|
||||
<title>Grinminer.net</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="title" property="og:title" content="grinminer.net">
|
||||
<meta name="Keywords" content="Grin, Mimblewimble, Mining, Solo, Pools, Ipollo, G1, Openwrt, Firmware, Wallet">
|
||||
<meta name="Description" content="An alternative to the corporate cloud providing VPS services and tools to assist solo Grin miners.">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="https://grin.mw/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="https://grin.mw/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="https://grin.mw/favicon-16x16.png">
|
||||
<link rel="manifest" href="https://grin.mw/site.webmanifest">
|
||||
<meta name="theme-color" content="#fef102">
|
||||
<!-- CSS Main -->
|
||||
<link rel="stylesheet" type="text/css" href="../main.css")>
|
||||
</head>
|
||||
|
||||
<body width="device-width">
|
||||
<!-- Load an icon library to show a hamburger menu (bars) on small screens -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
|
||||
<!--Navigation links-->
|
||||
<div class="topnav" id="myTopnav">
|
||||
<a href="https://grinminer.net/nodes/" class="active">Public Nodes</a>
|
||||
<a href="https://grinminer.net/api/" class="active">Public API</a>
|
||||
<a href="https://grinminer.net/application/" class="active">Node/VPS Application</a>
|
||||
<a href="https://grinminer.net/download/" class="active">Download Firmware/Wallets</a>
|
||||
<a href="https://explorer.grinminer.net" class="active">Mainnet Explorer</a>
|
||||
<a href="https://testexplorer.grinminer.net" class="active">Testnet Explorer</a>
|
||||
<a href="https://checker.grinminer.net" class="active">Wallet Checker</a>
|
||||
<a href="https://t.me/grinminer_net" class="grey">Telegram</a>
|
||||
<a href="https://github.com/transatoshi-mw/grinminer.net">Github</a>
|
||||
<a href="javascript:void(0);" class="icon" onclick="myFunction()">
|
||||
<i class="fa fa-bars"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<span class="cloud"><h2>Developed over 2 years to be an alternative to the corporate cloud.</h2></span>
|
||||
|
||||
<!--Banner-->
|
||||
<a href="https://grinminer.net"><img src="../images/web-banner.png" alt="grinminer-banner" class="responsive"></a>
|
||||
|
||||
<!--Subtitle-->
|
||||
<div class="content">
|
||||
<div class="subtitle">
|
||||
<h3>Provider of hosted public & private nodes + solo mining pools + a Trezor/Ledger compatible wallet.</h3>
|
||||
</div>
|
||||
<div class="corporate">
|
||||
<p>Host of Grin's permanent public testnet mining node allowing devs to have 24/7 block production, aiding development of the protocol.</p>
|
||||
</div>
|
||||
<p>VPS service with no KYC, customer logs, contracts, or corporate ties.</p>
|
||||
<div id="corporate">
|
||||
<span class="corporate"><p>Grinminer.net is not controlled by any company or foundation.</p></span>
|
||||
</div>
|
||||
<h1 class="fourohfour">404 NOT FOUND</h1>
|
||||
<img src="../images/grinminerbanner.png" alt="grinminer ad" class="ad">
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<footer width="device-width">
|
||||
<div class="footer">
|
||||
<p>Apply today or contact transatoshi via the Telegram link for more info on free and paid node/stratum hosting, or if you need tGrin for tesnet.</p>
|
||||
<p>mikkdfjjawqzw4bis5pwq
|
||||
<br>
|
||||
wsbul3ndubhnbwtlumaeo
|
||||
<br>
|
||||
wlcigxgwk7n4yd.onion</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</html>
|
88
website/api/index.html
Normal file
@@ -0,0 +1,88 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-P53NSV9J65"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-P53NSV9J65');
|
||||
</script>
|
||||
<title>Grinminer.net</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="title" property="og:title" content="grinminer.net">
|
||||
<meta name="Keywords" content="Grin, Mimblewimble, Mining, Solo, Pools, Ipollo, G1, Openwrt, Firmware, Wallet">
|
||||
<meta name="Description" content="An alternative to the corporate cloud providing VPS services and tools to assist solo Grin miners.">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="https://grin.mw/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="https://grin.mw/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="https://grin.mw/favicon-16x16.png">
|
||||
<link rel="manifest" href="https://grin.mw/site.webmanifest">
|
||||
<meta name="theme-color" content="#fef102">
|
||||
<!-- CSS Main -->
|
||||
<link rel="stylesheet" type="text/css" href="../main.css")>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
</head>
|
||||
|
||||
<body width="device-width">
|
||||
<!--Navigation links-->
|
||||
<div class="topnav" id="myTopnav">
|
||||
<a href="https://grinminer.net/nodes/" class="active">Public Nodes</a>
|
||||
<a href="https://grinminer.net/api/" class="active">Public API</a>
|
||||
<a href="https://grinminer.net/application/" class="active">Node/VPS Application</a>
|
||||
<a href="https://grinminer.net/download/" class="active">Download Firmware/Wallets</a>
|
||||
<a href="https://explorer.grinminer.net" class="active">Mainnet Explorer</a>
|
||||
<a href="https://testexplorer.grinminer.net" class="active">Testnet Explorer</a>
|
||||
<a href="https://checker.grinminer.net" class="active">Wallet Checker</a>
|
||||
<a href="https://t.me/grinminer_net" class="grey">Telegram</a>
|
||||
<a href="https://github.com/transatoshi-mw/grinminer.net">Github</a>
|
||||
<a href="javascript:void(0);" class="icon" onclick="myFunction()">
|
||||
<i class="fa fa-bars"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<span class="cloud"><h2>Developed over 2 years to be an alternative to the corporate cloud.</h2></span>
|
||||
|
||||
|
||||
<!--Banner-->
|
||||
<a href="https://grinminer.net"><img src="../images/web-banner.png" alt="grinminer-banner" class="responsive"></a>
|
||||
<!--Subtitle-->
|
||||
<div class="content">
|
||||
<div class="subtitle">
|
||||
<h3>Provider of hosted public & private nodes + solo mining pools + a Trezor/Ledger compatible wallet.</h3>
|
||||
</div>
|
||||
<h1>Grinminer public APIs</h1>
|
||||
<p>no API secret required</p>
|
||||
<h2>Mainnet</h2>
|
||||
<h3>http://grinminer.net:3413</h3>
|
||||
<h2>Testnet</h2>
|
||||
<h3>http://grinminer.net:13413</h3>
|
||||
<a href="https://github.com/mimblewimble/grin/blob/master/doc/api/node_api_v1.md">Grin node api v1 documentation</a>
|
||||
<br>
|
||||
<a href="https://docs.grin.mw/grin-rfcs/text/0007-node-api-v2/">Grin node api v2 documentation</a>
|
||||
<script>
|
||||
function myFunction() {
|
||||
var x = document.getElementById("myTopnav");
|
||||
if (x.className === "topnav") {
|
||||
x.className += " responsive"; // Add the "responsive" class
|
||||
} else {
|
||||
x.className = "topnav"; // Remove the "responsive" class
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
<footer width="device-width">
|
||||
<div class="footer">
|
||||
<p>Apply today or contact transatoshi via the Telegram link for more info on free and paid node/stratum hosting, or if you need tGrin for tesnet.</p>
|
||||
<p>mikkdfjjawqzw4bis5pwq
|
||||
<br>
|
||||
wsbul3ndubhnbwtlumaeo
|
||||
<br>
|
||||
wlcigxgwk7n4yd.onion</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</html>
|
127
website/application/index.html
Normal file
@@ -0,0 +1,127 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-P53NSV9J65"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-P53NSV9J65');
|
||||
</script>
|
||||
<title>Grinminer.net</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="title" property="og:title" content="grinminer.net">
|
||||
<meta name="Keywords" content="Grin, Mimblewimble, Mining, Solo, Pools, Ipollo, G1, Openwrt, Firmware, Wallet">
|
||||
<meta name="Description" content="An alternative to the corporate cloud providing VPS services and tools to assist solo Grin miners.">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="https://grin.mw/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="https://grin.mw/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="https://grin.mw/favicon-16x16.png">
|
||||
<link rel="manifest" href="https://grin.mw/site.webmanifest">
|
||||
<meta name="theme-color" content="#fef102">
|
||||
<!-- CSS Main -->
|
||||
<link rel="stylesheet" type="text/css" href="../main.css")>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
</head>
|
||||
|
||||
<body width="device-width">
|
||||
<!--Navigation links-->
|
||||
<<div class="topnav" id="myTopnav">
|
||||
<a href="https://grinminer.net/nodes/" class="active">Public Nodes</a>
|
||||
<a href="https://grinminer.net/api/" class="active">Public API</a>
|
||||
<a href="https://grinminer.net/application/" class="active">Node/VPS Application</a>
|
||||
<a href="https://grinminer.net/download/" class="active">Download Firmware/Wallets</a>
|
||||
<a href="https://explorer.grinminer.net" class="active">Mainnet Explorer</a>
|
||||
<a href="https://testexplorer.grinminer.net" class="active">Testnet Explorer</a>
|
||||
<a href="https://checker.grinminer.net" class="active">Wallet Checker</a>
|
||||
<a href="https://t.me/grinminer_net" class="grey">Telegram</a>
|
||||
<a href="https://github.com/transatoshi-mw/grinminer.net">Github</a>
|
||||
<a href="javascript:void(0);" class="icon" onclick="myFunction()">
|
||||
<i class="fa fa-bars"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<span class="cloud"><h2>Developed over 2 years to be an alternative to the corporate cloud.</h2></span>
|
||||
|
||||
|
||||
<!--Banner-->
|
||||
<a href="https://grinminer.net"><img src="../images/web-banner.png" alt="grinminer-banner" class="responsive"></a>
|
||||
<!--Subtitle-->
|
||||
<div class="content">
|
||||
<div class="subtitle">
|
||||
<h3>Provider of hosted public & private nodes + solo mining pools + a Trezor/Ledger compatible wallet.</h3>
|
||||
</div>
|
||||
<!--Title-->
|
||||
<form action="https://formsubmit.co/fc6589379f42ab354825f1184623a4eb" method="POST" style="border:1px solid #ccc">
|
||||
<div class="container">
|
||||
<h1>Sign Up</h1>
|
||||
<p>Please fill in this form to create an account.</p>
|
||||
<p>Fees are nominal, and meant to discourage resource waste. Must be paid in Grin.</p>
|
||||
<p>All nodes are LXC containers running the latest Debian release.</p>
|
||||
<br>
|
||||
<fieldset>
|
||||
<legend>Are you looking for a Grin node or node+stratum?</legend>
|
||||
<label><input id="node" type="radio" name="node" value="node" checked>Node only</label>
|
||||
<label><input id="node+stratum" type="radio" name="node" value="stratum">Node+Stratum</label>
|
||||
</fieldset>
|
||||
<br>
|
||||
<fieldset>
|
||||
<legend>Do you want an archival or pruned node?</legend>
|
||||
<input id="pruned" type="radio" name="type" value="pruned" checked> <label for="pruned">Pruned (free)</label>
|
||||
<input id="full" type="radio" name="type" value="archival"> <label for="archival">Archival (flat fee)</label>
|
||||
</fieldset>
|
||||
<br>
|
||||
<fieldset>
|
||||
<legend>Do you require node setup or support/backups?</legend>
|
||||
<input id="no" type="radio" name="support" value="no" checked> <label for="no">None (free)</label>
|
||||
<input id="setup" type="radio" name="support" value="setup"> <label for="setup">Setup only (flat fee)</label>
|
||||
<input id="setup+support" type="radio" name="support" value="ongoing"> <label for="ongoing"> Ongoing support/backups (monthly fee)</label>
|
||||
</fieldset>
|
||||
<br>
|
||||
<fieldset>
|
||||
<legend>Do you agree to only use your VPS for Grin software?</legend>
|
||||
<input id="no-agreement" type="radio" name="agreement" value="no" checked> <label for="no">No (comment why)</label>
|
||||
<input id="agreement" type="radio" name="agreement" value="yes"> <label for="yes">Yes</label>
|
||||
</fieldset>
|
||||
<br>
|
||||
<input type="text" name="username" placeholder="username" required>
|
||||
<br>
|
||||
<input type="text" name="email" placeholder="email address" required>
|
||||
<br>
|
||||
<input type="text" name="comments" placeholder="comments">
|
||||
<input type="hidden" name="_next" value="https://grinminer.net/thanks.html">
|
||||
<input type="hidden" name="_subject" value="Grinminer application">
|
||||
<p>Grinminer.net is very young and experimental, use at your own risk.</p>
|
||||
<p>Once applied you will receive an email response within 48 hours to confirm.</p>
|
||||
|
||||
<div class="clearfix">
|
||||
<button type="submit" class="signupbtn">Sign Up</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<script>
|
||||
function myFunction() {
|
||||
var x = document.getElementById("myTopnav");
|
||||
if (x.className === "topnav") {
|
||||
x.className += " responsive"; // Add the "responsive" class
|
||||
} else {
|
||||
x.className = "topnav"; // Remove the "responsive" class
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
<footer width="device-width">
|
||||
<div class="footer">
|
||||
<p>Apply today or contact transatoshi via the Telegram link for more info on free and paid node/stratum hosting, or if you need tGrin for tesnet.</p>
|
||||
<p>mikkdfjjawqzw4bis5pwq
|
||||
<br>
|
||||
wsbul3ndubhnbwtlumaeo
|
||||
<br>
|
||||
wlcigxgwk7n4yd.onion</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</html>
|
BIN
website/firmware/SDCARD-IPollo-G1-2.5.4-firmware.img
Normal file
BIN
website/firmware/SDCARD-Ipollo-G1-2.5.2-firmware.bin
Normal file
2479
website/firmware/WEBFLASH-Ipollo-G1-2.4.0-firmware.bin
Normal file
2479
website/firmware/WEBFLASH-Ipollo-G1-2.4.4-firmware.bin
Normal file
1861
website/firmware/WEBFLASH-Ipollo-G1-2.4.9-firmware.bin
Normal file
BIN
website/firmware/WEBFLASH-Ipollo-G1-2.5.2-firmware.img
Normal file
BIN
website/firmware/WEBFLASH-Ipollo-G1-2.5.4-firmware.bin
Normal file
11
website/grinminer-form/Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "grinminer-form"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
rocket = { git = "https://github.com/rwf2/Rocket" }
|
||||
|
||||
[dependencies.rocket_dyn_templates]
|
||||
version = "0.1.0"
|
||||
features = ["handlebars", "tera", "minijinja"]
|
151
website/grinminer-form/index.html
Normal file
@@ -0,0 +1,151 @@
|
||||
** start of undefined **
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header class="header">
|
||||
<h1 id="title" class="text-center">Grinminer.net application</h1>
|
||||
<p id="description" class="description text-center">
|
||||
Apply for a free or paid node/stratum depending on support level
|
||||
</p>
|
||||
</header>
|
||||
<form id="survey-form">
|
||||
<div class="form-group">
|
||||
<label id="name-label" for="name">Name</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
id="name"
|
||||
class="form-control"
|
||||
placeholder="Enter your name"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label id="email-label" for="email">Email</label>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
id="email"
|
||||
class="form-control"
|
||||
placeholder="Enter your Email"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label id="number-label" for="number">Number of nodes<span class="clue">(max 4)</span></label>
|
||||
<input
|
||||
type="number"
|
||||
name="nodes"
|
||||
id="number"
|
||||
min="1"
|
||||
max="4"
|
||||
class="form-control"
|
||||
placeholder="node"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<p>Select an option</p>
|
||||
<select id="dropdown" name="stratum" class="form-control" required>
|
||||
<option disabled selected value>Select features</option>
|
||||
<option value="testnet">Testnet node</option>
|
||||
<option value="testnet">Testnet node+mwixnet</option>
|
||||
<option value="pruned">Pruned node</option>
|
||||
<option value="node+stratum">Pruned node+stratum</option>
|
||||
<option value="fullnode">Full node (10ツ)</option>
|
||||
<option value="fullnode+stratum">Full node+stratum(10ツ)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<p>Do you need setup help and ongoing support your node(s)?</p>
|
||||
<label>
|
||||
<input
|
||||
name="setup"
|
||||
value="no"
|
||||
type="radio"
|
||||
class="input-radio"
|
||||
checked
|
||||
/>No</label>
|
||||
<label>
|
||||
<input
|
||||
name="setup"
|
||||
value="yes"
|
||||
type="radio"
|
||||
class="input-radio"
|
||||
checked
|
||||
/>Yes (25ツ)</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<p>Do you agree to only use this VPS for Grin?</p>
|
||||
<select id="agreement" name="agreement" class="form-control" required>
|
||||
<option disabled selected value>Select an option</option>
|
||||
<option value="challenges">Yes</option>
|
||||
<option value="projects">No</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<p>What future features are you interested in?<span class="clue">(Check all that apply)</span></p>
|
||||
<label>
|
||||
<input
|
||||
name="prefer"
|
||||
value="firmware-update"
|
||||
type="checkbox"
|
||||
class="input-checkbox"
|
||||
/>Updated firmware</label>
|
||||
<label>
|
||||
<input
|
||||
name="prefer"
|
||||
value="firmware-overclock"
|
||||
type="checkbox"
|
||||
class="input-checkbox"
|
||||
/>Overclocked firmware</label
|
||||
>
|
||||
<label
|
||||
><input
|
||||
name="prefer"
|
||||
value="stratumv2"
|
||||
type="checkbox"
|
||||
class="input-checkbox"
|
||||
/>Stratum V2</label
|
||||
>
|
||||
<label
|
||||
><input
|
||||
name="prefer"
|
||||
value="controlpanel"
|
||||
type="checkbox"
|
||||
class="input-checkbox"
|
||||
/>Mining control panel</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<p>Comments or suggestions?</p>
|
||||
<textarea
|
||||
id="comments"
|
||||
class="input-textarea"
|
||||
name="comment"
|
||||
placeholder="Enter your comments here..."></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button type="submit" id="submit" class="submit-button">
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
** end of undefined **
|
||||
|
||||
** start of undefined **
|
||||
|
||||
|
||||
|
||||
** end of undefined **
|
||||
|
97
website/grinminer-form/src/main.rs
Normal file
@@ -0,0 +1,97 @@
|
||||
#[macro_use] extern crate rocket;
|
||||
|
||||
use rocket::time::Date;
|
||||
use rocket::http::{Status, ContentType};
|
||||
use rocket::form::{Form, Contextual, FromForm, FromFormField, Context};
|
||||
use rocket::fs::{FileServer, TempFile, relative};
|
||||
|
||||
use rocket_dyn_templates::Template;
|
||||
|
||||
#[derive(Debug, FromForm)]
|
||||
struct Password<'v> {
|
||||
#[field(validate = len(6..))]
|
||||
#[field(validate = eq(self.second))]
|
||||
#[allow(unused)]
|
||||
first: &'v str,
|
||||
#[allow(unused)]
|
||||
#[field(validate = eq(self.first))]
|
||||
second: &'v str,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromFormField)]
|
||||
enum Rights {
|
||||
Public,
|
||||
Reserved,
|
||||
Exclusive,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromFormField)]
|
||||
enum Category {
|
||||
Biology,
|
||||
Chemistry,
|
||||
Physics,
|
||||
#[field(value = "CS")]
|
||||
ComputerScience,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromForm)]
|
||||
#[allow(dead_code)]
|
||||
struct Submission<'v> {
|
||||
#[field(validate = len(1..))]
|
||||
title: &'v str,
|
||||
date: Date,
|
||||
#[field(validate = len(1..=250))]
|
||||
r#abstract: &'v str,
|
||||
#[field(validate = ext(ContentType::PDF))]
|
||||
file: TempFile<'v>,
|
||||
#[field(validate = len(1..))]
|
||||
category: Vec<Category>,
|
||||
rights: Rights,
|
||||
ready: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromForm)]
|
||||
#[allow(dead_code)]
|
||||
struct Account<'v> {
|
||||
#[field(validate = len(1..))]
|
||||
name: &'v str,
|
||||
password: Password<'v>,
|
||||
#[field(validate = contains('@').or_else(msg!("invalid email address")))]
|
||||
email: &'v str,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromForm)]
|
||||
#[allow(dead_code)]
|
||||
struct Submit<'v> {
|
||||
account: Account<'v>,
|
||||
submission: Submission<'v>,
|
||||
}
|
||||
|
||||
#[get("/")]
|
||||
fn index() -> Template {
|
||||
Template::render("index", &Context::default())
|
||||
}
|
||||
|
||||
// NOTE: We use `Contextual` here because we want to collect all submitted form
|
||||
// fields to re-render forms with submitted values on error. If you have no such
|
||||
// need, do not use `Contextual`. Use the equivalent of `Form<Submit<'_>>`.
|
||||
#[post("/", data = "<form>")]
|
||||
fn submit<'r>(form: Form<Contextual<'r, Submit<'r>>>) -> (Status, Template) {
|
||||
let template = match form.value {
|
||||
Some(ref submission) => {
|
||||
println!("submission: {:#?}", submission);
|
||||
Template::render("success", &form.context)
|
||||
}
|
||||
None => Template::render("index", &form.context),
|
||||
};
|
||||
|
||||
(form.context.status(), template)
|
||||
}
|
||||
|
||||
#[launch]
|
||||
fn rocket() -> _ {
|
||||
rocket::build()
|
||||
.mount("/", routes![index, submit])
|
||||
.attach(Template::fairing())
|
||||
.mount("/", FileServer::from(relative!("/static")))
|
||||
}
|
193
website/grinminer-form/src/tests.rs
Normal file
@@ -0,0 +1,193 @@
|
||||
use std::fmt;
|
||||
use super::{rocket, FormInput, FormOption};
|
||||
|
||||
use rocket::local::blocking::Client;
|
||||
use rocket::http::ContentType;
|
||||
|
||||
impl fmt::Display for FormOption {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
FormOption::A => write!(f, "a"),
|
||||
FormOption::B => write!(f, "b"),
|
||||
FormOption::C => write!(f, "c"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! assert_form_eq {
|
||||
($client:expr, $form_str:expr, $expected:expr) => {{
|
||||
let res = $client.post("/")
|
||||
.header(ContentType::Form)
|
||||
.body($form_str)
|
||||
.dispatch();
|
||||
|
||||
assert_eq!(res.into_string(), Some($expected));
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! assert_valid_form {
|
||||
($client:expr, $input:expr) => {{
|
||||
let f = format!("checkbox={}&number={}&type={}&password={}&textarea={}&select={}",
|
||||
$input.checkbox, $input.number, $input.radio, $input.password,
|
||||
$input.text_area, $input.select);
|
||||
assert_form_eq!($client, &f, format!("{:?}", $input));
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! assert_valid_raw_form {
|
||||
($client:expr, $form_str:expr, $input:expr) => {{
|
||||
assert_form_eq!($client, $form_str, format!("{:?}", $input));
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_good_forms() {
|
||||
let client = Client::tracked(rocket()).unwrap();
|
||||
let mut input = FormInput {
|
||||
checkbox: true,
|
||||
number: 310,
|
||||
radio: FormOption::A,
|
||||
password: "beep".into(),
|
||||
text_area: "bop".to_string(),
|
||||
select: FormOption::B
|
||||
};
|
||||
|
||||
assert_valid_form!(&client, &input);
|
||||
|
||||
input.checkbox = false;
|
||||
assert_valid_form!(&client, &input);
|
||||
|
||||
input.number = 0;
|
||||
assert_valid_form!(&client, &input);
|
||||
input.number = 120;
|
||||
assert_valid_form!(&client, &input);
|
||||
input.number = 133;
|
||||
assert_valid_form!(&client, &input);
|
||||
|
||||
input.radio = FormOption::B;
|
||||
assert_valid_form!(&client, &input);
|
||||
input.radio = FormOption::C;
|
||||
assert_valid_form!(&client, &input);
|
||||
|
||||
input.password = "".into();
|
||||
assert_valid_form!(&client, &input);
|
||||
input.password = "----90138490285u2o3hndslkv".into();
|
||||
assert_valid_form!(&client, &input);
|
||||
input.password = "hi".into();
|
||||
assert_valid_form!(&client, &input);
|
||||
|
||||
input.text_area = "".to_string();
|
||||
assert_valid_form!(&client, &input);
|
||||
input.text_area = "----90138490285u2o3hndslkv".to_string();
|
||||
assert_valid_form!(&client, &input);
|
||||
input.text_area = "hey".to_string();
|
||||
assert_valid_form!(&client, &input);
|
||||
|
||||
input.select = FormOption::A;
|
||||
assert_valid_form!(&client, &input);
|
||||
input.select = FormOption::C;
|
||||
assert_valid_form!(&client, &input);
|
||||
|
||||
// checkbox need not be present; defaults to false; accepts 'on' and 'off'
|
||||
assert_valid_raw_form!(&client,
|
||||
"number=133&type=c&password=hi&textarea=hey&select=c",
|
||||
&input);
|
||||
|
||||
assert_valid_raw_form!(&client,
|
||||
"checkbox=off&number=133&type=c&password=hi&textarea=hey&select=c",
|
||||
&input);
|
||||
|
||||
input.checkbox = true;
|
||||
assert_valid_raw_form!(&client,
|
||||
"checkbox=on&number=133&type=c&password=hi&textarea=hey&select=c",
|
||||
&input);
|
||||
}
|
||||
|
||||
macro_rules! assert_invalid_form {
|
||||
($client:expr, $vals:expr) => {{
|
||||
let vals = $vals;
|
||||
let s = format!("checkbox={}&number={}&type={}&password={}&textarea={}&select={}",
|
||||
vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]);
|
||||
assert_form_eq!($client, &s, format!("Invalid form input: {}", s));
|
||||
*vals = ["true", "1", "a", "hi", "hey", "b"];
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! assert_invalid_raw_form {
|
||||
($client:expr, $form_str:expr) => {{
|
||||
assert_form_eq!($client, $form_str, format!("Invalid form input: {}", $form_str));
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_semantically_invalid_forms() {
|
||||
let client = Client::tracked(rocket()).unwrap();
|
||||
let mut form_vals = ["true", "1", "a", "hi", "hey", "b"];
|
||||
|
||||
form_vals[0] = "not true";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
form_vals[0] = "bing";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
form_vals[0] = "true0";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
form_vals[0] = " false";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
|
||||
form_vals[1] = "-1";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
form_vals[1] = "1e10";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
form_vals[1] = "-1-1";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
form_vals[1] = "NaN";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
|
||||
form_vals[2] = "A?";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
form_vals[2] = " B";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
form_vals[2] = "d";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
form_vals[2] = "100";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
form_vals[2] = "";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
|
||||
// password and textarea are always valid, so we skip them
|
||||
form_vals[5] = "A.";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
form_vals[5] = "b ";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
form_vals[5] = "d";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
form_vals[5] = "-a";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
form_vals[5] = "";
|
||||
assert_invalid_form!(&client, &mut form_vals);
|
||||
|
||||
// now forms with missing fields
|
||||
assert_invalid_raw_form!(&client, "number=10&type=a&password=hi&textarea=hey");
|
||||
assert_invalid_raw_form!(&client, "number=10&radio=a&password=hi&textarea=hey&select=b");
|
||||
assert_invalid_raw_form!(&client, "number=10&password=hi&select=b");
|
||||
assert_invalid_raw_form!(&client, "number=10&select=b");
|
||||
assert_invalid_raw_form!(&client, "password=hi&select=b");
|
||||
assert_invalid_raw_form!(&client, "password=hi");
|
||||
assert_invalid_raw_form!(&client, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_structurally_invalid_forms() {
|
||||
let client = Client::tracked(rocket()).unwrap();
|
||||
assert_invalid_raw_form!(&client, "==&&&&&&==");
|
||||
assert_invalid_raw_form!(&client, "a&=b");
|
||||
assert_invalid_raw_form!(&client, "=");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_bad_utf8() {
|
||||
let client = Client::tracked(rocket()).unwrap();
|
||||
unsafe {
|
||||
let bad_str = std::str::from_utf8_unchecked(b"a=\xff");
|
||||
assert_form_eq!(&client, bad_str, "Form input was invalid UTF-8.".into());
|
||||
}
|
||||
}
|
1
website/grinminer-form/static/chota.min.css
vendored
Normal file
148
website/grinminer-form/templates/index.html.tera
Normal file
@@ -0,0 +1,148 @@
|
||||
{% import "macros" as m %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>Rocket Form Example</title>
|
||||
<link rel="stylesheet" href="/chota.min.css">
|
||||
<style>
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px 10px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 10px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Form Example</h1>
|
||||
|
||||
{% if errors | length > 0 %}
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<small class="text-error">
|
||||
error: {{ errors | length }} field{{ errors | length | pluralize }}
|
||||
failed to validate
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form action="/" method="post" enctype="multipart/form-data">
|
||||
<fieldset>
|
||||
<legend>About You</legend>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
{{ m::input(label="Name", type="text", name="account.name") }}
|
||||
<!-- required -->
|
||||
</div>
|
||||
<div class="col">
|
||||
{{ m::input(label="Email Address", type="text", name="account.email") }}
|
||||
<!-- required pattern=".*@.*"/> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
{{ m::input(label="Password", type="password", name="account.password.first") }}
|
||||
<!-- required minlength="6" value="" /> -->
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
|
||||
{{
|
||||
m::input(label="Confirm Password",
|
||||
type="password",
|
||||
name="account.password.second")
|
||||
}}
|
||||
|
||||
<!-- required minlength="6" value="" /> -->
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>Metadata</legend>
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
{{ m::input(label="Title", type="text", name="submission.title") }}
|
||||
<!-- required -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
{{ m::input(label="Publish Date", type="date", name="submission.date") }}
|
||||
<!-- <input type="date" name="submission.date" id="date" value="2020-12-26"> -->
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
{{
|
||||
m::select(
|
||||
label="Rights Assignment",
|
||||
name="submission.rights",
|
||||
options=["Public", "Reserved", "Exclusive"]
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label>Applicable Categories</label>
|
||||
<br />
|
||||
{{ m::checkbox(name="submission.category", label="Biology", value="Biology") }}
|
||||
<br />
|
||||
{{ m::checkbox(name="submission.category", label="Chemistry", value="Chemistry") }}
|
||||
<br />
|
||||
{{ m::checkbox(name="submission.category", label="Physics", value="Physics") }}
|
||||
<br />
|
||||
{{ m::checkbox(name="submission.category", label="CS", value="CS") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>Contents</legend>
|
||||
|
||||
{{
|
||||
m::textarea(
|
||||
label="Abstract",
|
||||
name="submission.abstract",
|
||||
placeholder="Your abstract, max 250 characters...",
|
||||
max=250
|
||||
)
|
||||
}}
|
||||
|
||||
{{
|
||||
m::input(
|
||||
label="File to Upload (PDF, max 1MiB)",
|
||||
type="file",
|
||||
name="submission.file"
|
||||
)
|
||||
}}
|
||||
|
||||
<!-- <input type="file" name="submission.file" id="file" required accept=".pdf"> -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
{{ m::checkbox(name="submission.ready", label="Submission is ready for review.") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<br />
|
||||
<input type="submit" value="Submit" class="is-full-width" />
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
63
website/grinminer-form/templates/macros.html.tera
Normal file
@@ -0,0 +1,63 @@
|
||||
{% macro value_for(name) %}
|
||||
{%- if name in values -%}
|
||||
{{- values | get(key=name) | first -}}
|
||||
{%- endif -%}
|
||||
{% endmacro value_for %}
|
||||
|
||||
{% macro errors_for(name) %}
|
||||
{%- if name in errors -%}
|
||||
{% set field_errors = errors | get(key=name) %}
|
||||
{% for error in field_errors %}
|
||||
<p class="text-error is-marginless">{{ error.msg }}</p>
|
||||
{% endfor %}
|
||||
{%- endif -%}
|
||||
{% endmacro errors_for %}
|
||||
|
||||
{% macro input(type, label, name, value="") %}
|
||||
<label for="{{ name }}">{{ label }}</label>
|
||||
<input type="{{ type }}"
|
||||
name="{{ name }}"
|
||||
id="{{ name }}"
|
||||
value='{{ self::value_for(name=name) }}'
|
||||
{% if name in errors %} class="error" {% endif %}
|
||||
/>
|
||||
|
||||
{{ self::errors_for(name=name) }}
|
||||
{% endmacro input %}
|
||||
|
||||
{% macro checkbox(name, label, value="yes") %}
|
||||
<label {% if name in errors %} class="bd-error" {% endif %}>
|
||||
<input type="checkbox" name="{{ name }}" value={{ value }}
|
||||
{% if name in values %}
|
||||
{% set field_values = values | get(key=name) %}
|
||||
{% if field_values is containing(value) %}
|
||||
checked
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
>
|
||||
{{ label }}
|
||||
</label>
|
||||
{% endmacro checkbox %}
|
||||
|
||||
{% macro textarea(label, name, placeholder="", max=250) %}
|
||||
<label for="{{ name }}">{{ label }}</label>
|
||||
<textarea placeholder="{{ placeholder }}"
|
||||
name="{{ name }}" id="{{ name }}" rows="8" cols="40"
|
||||
{% if name in errors %} class="error" {% endif %}
|
||||
>
|
||||
{{- self::value_for(name=name) -}}
|
||||
</textarea>
|
||||
|
||||
{{ self::errors_for(name=name) }}
|
||||
{% endmacro textarea %}
|
||||
|
||||
{% macro select(label, name, options) %}
|
||||
<label for="{{ name }}">{{ label }}</label>
|
||||
<select name="{{ name }}" id="{{ name }}">
|
||||
{% for value in options %}
|
||||
<option value="{{ value }}"
|
||||
{% if self::value_for(name=name) == value %} selected {% endif %}
|
||||
>{{ value }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% endmacro select %}
|
30
website/grinminer-form/templates/success.html.tera
Normal file
@@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>Rocket Form Example</title>
|
||||
<link rel="stylesheet" href="/chota.min.css">
|
||||
<style>
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Success!</h1>
|
||||
|
||||
<h3>Submission Data</h3>
|
||||
|
||||
<ul>
|
||||
{% for key, value in values %}
|
||||
<li><strong>{{ key }}</strong> - {{ value }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<a href="/">< Submit Another</a>
|
||||
</body>
|
||||
</html>
|
BIN
website/images/gpp.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
website/images/grim.png
Normal file
After Width: | Height: | Size: 130 KiB |
BIN
website/images/grin-logo-cat-cropped-black.png
Normal file
After Width: | Height: | Size: 84 KiB |
1605
website/images/grin-logo-cat.svg
Normal file
After Width: | Height: | Size: 119 KiB |
BIN
website/images/grinminerbanner.png
Normal file
After Width: | Height: | Size: 622 KiB |
BIN
website/images/ipollo.png
Normal file
After Width: | Height: | Size: 8.8 KiB |
BIN
website/images/network.png
Normal file
After Width: | Height: | Size: 252 KiB |
4
website/images/network.svg
Normal file
After Width: | Height: | Size: 4.3 MiB |
BIN
website/images/web-banner.png
Executable file
After Width: | Height: | Size: 128 KiB |
224
website/main.css
Normal file
@@ -0,0 +1,224 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Lato", sans-serif;
|
||||
background-color: black;
|
||||
color: #fef102;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: monospace;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: whitesmoke;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
width: 430px;
|
||||
}
|
||||
|
||||
/* Add a black background color to the top navigation */
|
||||
.topnav {
|
||||
background-color: #333;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Style the links inside the navigation bar */
|
||||
.topnav a {
|
||||
float: left;
|
||||
display: block;
|
||||
color: whitesmoke;
|
||||
text-align: center;
|
||||
padding: 14px 16px;
|
||||
text-decoration: none;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
/* Change the color of links on hover */
|
||||
.topnav a:hover {
|
||||
background-color: #fef102;
|
||||
color: black;
|
||||
}
|
||||
|
||||
/* Add an active class to highlight the current page */
|
||||
.topnav a.active {
|
||||
background-color: #fef102;
|
||||
color: black;
|
||||
border-right: black 2px solid;
|
||||
}
|
||||
|
||||
/* Add an active class to highlight the current page */
|
||||
.topnav a.grey {
|
||||
border-right: black 2px solid;
|
||||
}
|
||||
|
||||
.responsive {
|
||||
max-width: 90%;
|
||||
height: auto;
|
||||
margin: 0 auto;
|
||||
border: #fef102 solid 4px;
|
||||
border-radius: 30px;
|
||||
box-shadow:0 0 10px #fef102;
|
||||
text-align: center;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.diagram {
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.fourohfour {
|
||||
font-size: 80px;
|
||||
}
|
||||
|
||||
.ad {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-family: monospace;
|
||||
font-size: 16px
|
||||
font-weight: 800;
|
||||
border: #fef102 solid 4px;
|
||||
border-radius: 0 0 15px 15px;
|
||||
box-shadow: 0 0 10px #fef102;
|
||||
width: 70%;
|
||||
height: auto;
|
||||
margin: -5px auto 30px auto;
|
||||
display: block;
|
||||
text-align:center;
|
||||
padding: 0 40px 0 40px;
|
||||
}
|
||||
|
||||
div.content {
|
||||
text-align: center;
|
||||
padding: 1px 16px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cloud {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
color: black;
|
||||
display: block;
|
||||
background-color: #fef102;
|
||||
}
|
||||
|
||||
.nodes {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.site.pad.community-pad{
|
||||
padding-top:40px;
|
||||
padding-bottom:40px;
|
||||
border-top:1px solid black;
|
||||
}
|
||||
|
||||
.community {
|
||||
background-color:black;
|
||||
padding:-10px 16px 64px 16px;
|
||||
max-width:700px;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.community a {
|
||||
border-bottom:1px solid black
|
||||
}
|
||||
|
||||
.community h2 {
|
||||
text-align:center
|
||||
}
|
||||
|
||||
.community-subheading {
|
||||
line-height:1.4em;
|
||||
text-align:center
|
||||
}
|
||||
|
||||
.community-content {
|
||||
margin-top:40px;
|
||||
background-color:black;
|
||||
}
|
||||
|
||||
.community-row {
|
||||
padding:20px;
|
||||
margin: 5px 0 5px 0;
|
||||
display:flex;
|
||||
flex-direction: column;
|
||||
border: solid 1px silver;
|
||||
}
|
||||
|
||||
.community-row-img {
|
||||
height:80px;
|
||||
width:80px;
|
||||
margin-right:16px;
|
||||
border-radius:15px
|
||||
}
|
||||
|
||||
.community-row-content {
|
||||
margin-top:4px
|
||||
}
|
||||
|
||||
.community-row-heading {
|
||||
font-size:18px;
|
||||
font-weight:bold;
|
||||
margin-bottom:4px
|
||||
}
|
||||
|
||||
.community-row-desc {
|
||||
line-height:1.4em;
|
||||
margin-bottom:8px
|
||||
}
|
||||
|
||||
.community-row-category {
|
||||
color:#6F6F6F;
|
||||
font-size:12px
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.topnav {
|
||||
overflow: hidden;
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.topnav a {
|
||||
float: left;
|
||||
display: block;
|
||||
color: whitesmoke;
|
||||
text-align: center;
|
||||
padding: 14px 16px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.topnav a:hover {
|
||||
background-color: #fef102;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.topnav .icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Responsive styles */
|
||||
@media screen and (max-width: 600px) {
|
||||
.topnav a {
|
||||
display: none; /* Hide all links by default */
|
||||
}
|
||||
.topnav a.icon {
|
||||
float: right;
|
||||
display: block; /* Show the hamburger icon */
|
||||
color: #fef102;
|
||||
}
|
||||
.topnav.responsive {
|
||||
position: relative;
|
||||
}
|
||||
.topnav.responsive a {
|
||||
display: block; /* Show links when the menu is responsive */
|
||||
float: none; /* Remove float */
|
||||
}
|
||||
}
|
87
website/thanks.html
Normal file
@@ -0,0 +1,87 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-P53NSV9J65"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-P53NSV9J65');
|
||||
</script>
|
||||
<title>Grinminer.net</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="title" property="og:title" content="grinminer.net">
|
||||
<meta name="Keywords" content="Grin, Mimblewimble, Mining, Solo, Pools, Ipollo, G1, Openwrt, Firmware, Wallet">
|
||||
<meta name="Description" content="An alternative to the corporate cloud providing VPS services and tools to assist solo Grin miners.">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="https://grin.mw/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="https://grin.mw/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="https://grin.mw/favicon-16x16.png">
|
||||
<link rel="manifest" href="https://grin.mw/site.webmanifest">
|
||||
<meta name="theme-color" content="#fef102">
|
||||
<!-- CSS Main -->
|
||||
<link rel="stylesheet" type="text/css" href="../main.css")>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
</head>
|
||||
|
||||
<body width="device-width">
|
||||
<body width="device-width">
|
||||
<!-- Load an icon library to show a hamburger menu (bars) on small screens -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
|
||||
<!--Navigation links-->
|
||||
<div class="topnav" id="myTopnav">
|
||||
<a href="https://grinminer.net/nodes/" class="active">Public Nodes</a>
|
||||
<a href="https://grinminer.net/api/" class="active">Public API</a>
|
||||
<a href="https://grinminer.net/application/" class="active">Node/VPS Application</a>
|
||||
<a href="https://grinminer.net/download/" class="active">Download Firmware/Wallets</a>
|
||||
<a href="https://explorer.grinminer.net" class="active">Mainnet Explorer</a>
|
||||
<a href="https://testexplorer.grinminer.net" class="active">Testnet Explorer</a>
|
||||
<a href="https://checker.grinminer.net" class="active">Wallet Checker</a>
|
||||
<a href="https://t.me/grinminer_net" class="grey">Telegram</a>
|
||||
<a href="https://github.com/transatoshi-mw/grinminer.net">Github</a>
|
||||
<a href="javascript:void(0);" class="icon" onclick="myFunction()">
|
||||
<i class="fa fa-bars"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<span class="cloud"><h2>Developed over 2 years to be an alternative to the corporate cloud.</h2></span>
|
||||
|
||||
<!--Banner-->
|
||||
<a href="https://grinminer.net"><img src="../images/web-banner.png" alt="grinminer-banner" class="responsive"></a>
|
||||
|
||||
<!--Subtitle-->
|
||||
<div class="content">
|
||||
<div class="subtitle">
|
||||
<h3>Provider of hosted public & private nodes + solo mining pools + a Trezor/Ledger compatible wallet.</h3>
|
||||
</div>
|
||||
<!--Title-->
|
||||
<div class="nodes">
|
||||
<h1>Thank you! Expect a response within 48hr.</h1>
|
||||
</div>
|
||||
<script>
|
||||
function myFunction() {
|
||||
var x = document.getElementById("myTopnav");
|
||||
if (x.className === "topnav") {
|
||||
x.className += " responsive"; // Add the "responsive" class
|
||||
} else {
|
||||
x.className = "topnav"; // Remove the "responsive" class
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
<footer width="device-width">
|
||||
<div class="footer">
|
||||
<p>Apply today or contact transatoshi via the Telegram link for more info on free and paid node/stratum hosting, or if you need tGrin for tesnet.</p>
|
||||
<p>mikkdfjjawqzw4bis5pwq
|
||||
<br>
|
||||
wsbul3ndubhnbwtlumaeo
|
||||
<br>
|
||||
wlcigxgwk7n4yd.onion</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</html>
|