Account portal, download page, non-standard module docs

This ends v1 on the website. Docs archive still available through a
sidebar nav link in the docs.
This commit is contained in:
Matthew Holt 2020-07-16 15:51:46 -06:00
parent 49ed10d267
commit 4f6d355a97
No known key found for this signature in database
GPG key ID: 2A349DD577D586A5
37 changed files with 1678 additions and 56 deletions

28
src/account/create.html Normal file
View file

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>Create Account - Caddy</title>
{{include "/includes/account-head.html"}}
<script src="/resources/js/account/create.js"></script>
</head>
<body>
<form action="/api/create-account" class="card">
<section class="head">
<a href="/"><img src="/resources/images/caddy-lock.png" alt="Caddy Portal" class="logo"></a>
</section>
<section>
<h1>Create Account</h1>
or <a href="/account/login">log in</a>
<div class="form-fields">
<input type="text" name="name" id="name" placeholder="Name">
<input type="email" name="email" id="email" placeholder="Email address" required>
<input type="password" name="password" placeholder="Password" required>
<button type="submit" id="submit" class="blue">Create Account</button>
<p>
We will send you an email to verify your account.
</p>
</div>
</section>
</form>
</body>
</html>

32
src/account/index.html Normal file
View file

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<title>Dashboard - Caddy</title>
{{include "/includes/account-head.html"}}
<link rel="stylesheet" href="/resources/css/account/dashboard.css">
<script src="/resources/js/account/dashboard.js"></script>
</head>
<body>
<div class="container">
{{include "/includes/account-nav.html"}}
<main class="dashboard">
<section>
<h1 class="pad">Your packages<a href="/account/register-package" class="gray button float-right">Register package</a></h1>
<table id="user-packages">
<tr>
<th>Import path</th>
<th class="text-center"><span class="help" title="Whether package and module documentation is visible on the website.">Listed</span></th>
<th class="text-center"><span class="help" title="Whether visitors can download Caddy with this package plugged in.">Available</span></th>
<th>Downloads</th>
<th></th>
</tr>
<!-- Filled by JS -->
</table>
<!-- <div class="text-right pad">
<a href="/account/register-package" class="gray button">Register package</a>
</div> -->
</section>
</main>
</div>
</body>
</html>

25
src/account/login.html Normal file
View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>Log In - Caddy</title>
{{include "/includes/account-head.html"}}
<script src="/resources/js/account/login.js"></script>
</head>
<body>
<form action="/api/login" class="card">
<section class="head">
<a href="/"><img src="/resources/images/caddy-lock.png" alt="Caddy Portal" class="logo"></a>
</section>
<section>
<h1>Log In</h1>
or <a href="/account/create">create account</a>
<div class="form-fields">
<input type="email" name="email" id="email" placeholder="Email address" required>
<input type="password" name="password" placeholder="Password" required>
<button type="submit" id="submit" class="blue">Log In</button>
<a href="/account/reset-password">Reset password</a>
</div>
</section>
</form>
</body>
</html>

11
src/account/logout.html Normal file
View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>Logout - Caddy</title>
{{include "/includes/account-head.html"}}
<script src="/resources/js/account/logout.js"></script>
</head>
<body>
Logging out...
</body>
</html>

View file

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<title>Register Package - Caddy</title>
{{include "/includes/account-head.html"}}
<script src="/resources/js/account/register-package.js"></script>
</head>
<body>
<div class="container">
{{include "/includes/account-nav.html"}}
<main>
<section>
<form action="/api/claim-package">
<div class="form-fields">
<div class="field">
<label>
<b>Package import path</b>
<input type="text" name="package" required>
</label>
<div class="description">
You must use <a href="https://github.com/golang/go/wiki/Modules#semantic-import-versioning" target="_blank">semantic import versioning</a>. Basically, this means if your module is at v2 or higher the import path must be suffixed with <b>/vN</b> (where <b>N</b> is the major version number).
</div>
</div>
<div class="field">
<label>
<b>Version</b>
<input type="text" name="version" placeholder="latest">
</label>
<div class="description">
Optional. Any version string recognized by <a href="https://github.com/golang/go/wiki/Modules#version-selection">Go module</a> tooling is acceptable.
</div>
</div>
<div class="text-center">
<button type="submit" id="submit" class="blue">Claim Package</button>
</div>
</div>
</form>
</section>
</main>
</div>
</body>
</html>

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<title>Reset Password - Caddy</title>
{{include "/includes/account-head.html"}}
<script src="/resources/js/account/reset-password.js"></script>
</head>
<body>
<form action="/api/reset-password" class="card" id="reset-password-step1">
<section class="head">
<a href="/"><img src="/resources/images/caddy-lock.png" alt="Caddy Portal" class="logo"></a>
</section>
<section>
<h1>Reset Password</h1>
<a href="javascript:" id="goto-step2">I already have a reset token</a>
<div class="form-fields">
<input type="email" name="email" id="email-step1" placeholder="Email address" required>
<button type="submit" id="submit" class="blue">Continue</button>
</div>
</section>
</form>
<form action="/api/reset-password" class="card" id="reset-password-step2">
<section class="head">
<a href="/"><img src="/resources/images/caddy-lock.png" alt="Caddy Portal" class="logo"></a>
</section>
<section>
<h1>Reset Password</h1>
<a href="javascript:" id="goto-step1">I still need a reset token</a>
<div class="form-fields">
<input type="email" name="email" id="email-step2" placeholder="Email address" required>
<input type="text" name="token" id="token" placeholder="Token" required>
<input type="password" name="password" placeholder="New Password" required>
<button type="submit" id="submit" class="blue">Finish Reset</button>
</div>
</section>
</form>
</body>
</html>

24
src/account/verify.html Normal file
View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<title>Confirm Account - Caddy</title>
{{include "/includes/account-head.html"}}
<script src="/resources/js/account/verify.js"></script>
</head>
<body>
<form action="/api/verify-account" class="card">
<section class="head">
<a href="/"><img src="/resources/images/caddy-lock.png" alt="Caddy Portal" class="logo"></a>
</section>
<section>
<h1>Confirm Account</h1>
or <a href="/account/login">log in</a>
<div class="form-fields">
<input type="email" name="email" id="email" placeholder="Email address" required>
<input type="text" name="account_id" placeholder="Account ID" required>
<button type="submit" id="submit" class="blue">Confirm</button>
</div>
</section>
</form>
</body>
</html>

88
src/download.html Normal file
View file

@ -0,0 +1,88 @@
<!DOCTYPE html>
<html>
<head>
<title>Download Caddy</title>
{{include "/includes/head.html"}}
<link rel="stylesheet" href="/resources/css/download.css">
<script src="/resources/js/jquery-3.4.1.min.js"></script>
<script src="/resources/js/sweetalert.min.js"></script>
<script src="/resources/js/download.js"></script>
</head>
<body>
<div class="wrapper">
<header>
<div id="logo-container">
<a href="/"><img src="/resources/images/caddy-wordmark.svg" id="logo" alt="Caddy"></a>
</div>
{{include "/includes/header-nav.html"}}
</header>
<div class="download-bar">
<div>
<div>
<b>Platform:</b>
<select size="1" id="platform">
<option></option>
<option value="dragonfly-amd64">Dragonfly amd64</option>
<option value="freebsd-amd64">FreeBSD amd64</option>
<option value="freebsd-arm-6">FreeBSD arm 6</option>
<option value="freebsd-arm-7">FreeBSD arm 7</option>
<option value="freebsd-arm64">FreeBSD arm64</option>
<option value="linux-amd64">Linux amd64</option>
<option value="linux-arm-5">Linux arm 5</option>
<option value="linux-arm-6">Linux arm 6</option>
<option value="linux-arm-7">Linux arm 7</option>
<option value="linux-arm64">Linux arm64</option>
<option value="linux-mips">Linux mips</option>
<option value="linux-mips64">Linux mips64</option>
<option value="linux-mips64le">Linux mips64le</option>
<option value="linux-mipsle">Linux mipsle</option>
<option value="linux-ppc64">Linux ppc64</option>
<option value="linux-ppc64le">Linux ppc64le</option>
<option value="linux-s390x">Linux s390x</option>
<option value="darwin-amd64">macOS amd64</option>
<option value="openbsd-amd64">OpenBSD amd64</option>
<option value="openbsd-arm-6">OpenBSD arm 6</option>
<option value="openbsd-arm-7">OpenBSD arm 7</option>
<option value="openbsd-arm64">OpenBSD arm64</option>
<option value="plan9-amd64">Plan9 amd64</option>
<option value="plan9-arm-6">Plan9 arm 6</option>
<option value="plan9-arm-7">Plan9 arm 7</option>
<option value="solaris-amd64">Solaris amd64</option>
<option value="windows-amd64">Windows amd64</option>
<option value="windows-arm-6">Windows arm 6</option>
<option value="windows-arm-7">Windows arm 7</option>
</select>
</div>
</div>
<div>
<div>
<b>Additional packages:</b> <span id="package-count">0</span>
</div>
</div>
<div>
<a href="/api/download" class="blue button" id="download">Download</a>
</div>
</div>
<div class="packages-explanation">
Always comes with all standard <a href="/docs/modules">Caddy modules</a>.
<br><br>
Optionally select additional packages to include in your build: <span class="warning">⚠️ Only choose plugins you need and trust</span>
</div>
<div class="table-container">
<table id="optional-packages">
<tr>
<th>Package</th>
<th class="text-center">Version</th>
<th>Modules</th>
</tr>
<!-- Populated by JS -->
</table>
</div>
</div>
{{include "/includes/footer.html"}}
</body>
</html>

View file

@ -0,0 +1,5 @@
{{include "/includes/head.html"}}
<link rel="stylesheet" href="/resources/css/account/common.css">
<script src="/resources/js/jquery-3.4.1.min.js"></script>
<script src="/resources/js/sweetalert.min.js"></script>
<script src="/resources/js/account/common.js"></script>

View file

@ -0,0 +1,16 @@
<nav>
<div class="logo-container">
<img src="/resources/images/caddy-lock.png" alt="Caddy Portal" title="Caddy Portal" class="logo">
<br>
<b>Portal</b>
<br>
<span class="help beta" title="Still experimental; subject to change or reset. Thanks for your patience and understanding.">(beta)</span>
</div>
<ul>
<li><a href="/account/">🎛 Dashboard</a></li>
<li><a href="/account/register-package">📦 Register Package</a></li>
<li><a href="/account/logout">🔒 Log Out</a></li>
<br>
<li><a href="/">⬅️ Main Site</a></li>
</ul>
</nav>

View file

@ -1,3 +1,11 @@
<div>
<div class="nonstandard-notice">
<b>This module does not come with Caddy.</b> It can be added by using <b><a href="/docs/build#xcaddy">xcaddy</a></b> or our <b><a href="/download">download page</a></b>. Non-standard modules may be developed by the community and are not officially endorsed or maintained by the Caddy project. The documentation is shown here only as a courtesy.
<br><br>
<b>Module repository: <a href="javascript:" class="nonstandard-project-link"></a></b>
</div>
</div>
<h2 id="docs">Description</h2> <h2 id="docs">Description</h2>
<div id="top-doc"> <div id="top-doc">
<!--Populated by JS--> <!--Populated by JS-->

View file

@ -1,4 +1,3 @@
{{include "/includes/v1-banner.html"}}
<header> <header>
<div id="logo-container"> <div id="logo-container">
<a href="/"><img src="/resources/images/caddy-wordmark.svg" id="logo" alt="Caddy"></a> <a href="/"><img src="/resources/images/caddy-wordmark.svg" id="logo" alt="Caddy"></a>

View file

@ -56,5 +56,7 @@
</ul> </ul>
</li> </li>
<li><a href="/docs/extending-caddy/namespaces">Module Namespaces</a></li> <li><a href="/docs/extending-caddy/namespaces">Module Namespaces</a></li>
<br>
<li><a href="/caddy-v1-docs-archive.tar.gz">v1 Docs <img src="/resources/images/external-link.svg"></a></li>
</ul> </ul>
</nav> </nav>

View file

@ -2,10 +2,10 @@
<nav> <nav>
<input type="search" id="search" placeholder="🔍 Search..."> <input type="search" id="search" placeholder="🔍 Search...">
<a href="/v2">v2 <span class="new">new</span></a> <a href="/v2">v2 <span class="new">new</span></a>
<a href="/docs/download">Download</a> <a href="/download">Download</a>
<a href="/docs/">Documentation</a> <a href="/docs/">Documentation</a>
<a href="https://caddy.community">Forum</a>
<a href="https://github.com/caddyserver/caddy">GitHub</a> <a href="https://github.com/caddyserver/caddy">GitHub</a>
<a href="https://caddy.community">Community</a> <a href="/account/">Account</a>
<a href="/v1/">v1</a>
<a href="/business" class="red button">For business</a> <a href="/business" class="red button">For business</a>
</nav> </nav>

View file

@ -1 +0,0 @@
<a href="/v1/" id="v1-banner"><b>This page is about Caddy 2.</b> If you still need v1 docs for a limited time, click here.</b></a>

View file

@ -9,7 +9,6 @@
</head> </head>
<body> <body>
<div class="hero"> <div class="hero">
{{include "/includes/v1-banner.html"}}
<div class="wrapper"> <div class="wrapper">
<header> <header>
<div id="logo-container"> <div id="logo-container">
@ -24,13 +23,11 @@
</h2> </h2>
<div class="download-container"> <div class="download-container">
<a href="/docs/download" class="big blue button">Download</a> <a href="/download" class="big blue button">Download</a>
<br>
then <a href="/docs/getting-started">learn how to get started</a>
<br><br><br>
<a href="https://github.com/caddyserver/caddy/releases/v1.0.5" class="gray button">Download v1.0 (obsolete)</a>
<iframe src="https://ghbtns.com/github-btn.html?user=caddyserver&repo=caddy&type=star&count=true&size=large" frameborder="0" scrolling="0" width="160px" height="30px" class="github-stars"></iframe> <iframe src="https://ghbtns.com/github-btn.html?user=caddyserver&repo=caddy&type=star&count=true&size=large" frameborder="0" scrolling="0" width="160px" height="30px" class="github-stars"></iframe>
<br> <br>
then <b><a href="/docs/getting-started">learn how to get started</a></b>
<br><br>
<small>Caddy is licensed with the Apache 2.0 open source license.</small> <small>Caddy is licensed with the Apache 2.0 open source license.</small>
</div> </div>
</div> </div>
@ -74,7 +71,7 @@
<!-- <p> <!-- <p>
A hardened TLS stack powered by the Go standard library serves a significant portion of all Internet traffic. A hardened TLS stack powered by the Go standard library serves a significant portion of all Internet traffic.
</p> --> </p> -->
<p><a href="/docs/download" class="blue button">Download</a></p> <p><a href="/download" class="blue button">Download</a></p>
</div> </div>
<img src="/resources/images/caddy-circle-lock.svg" alt="Caddy is the only server to use HTTPS automatically and by default"> <img src="/resources/images/caddy-circle-lock.svg" alt="Caddy is the only server to use HTTPS automatically and by default">
</div> </div>
@ -113,7 +110,7 @@
<p> <p>
Or use it as a dynamic reverse proxy to any number of backends, complete with active and passive health checks, load balancing, circuit breaking, caching, and more. Or use it as a dynamic reverse proxy to any number of backends, complete with active and passive health checks, load balancing, circuit breaking, caching, and more.
</p> </p>
<p><a href="/docs/download" class="blue button">Download</a></p> <p><a href="/download" class="blue button">Download</a></p>
</div> </div>
<img src="/resources/images/proxy-file-server.svg" alt="Caddy is the only server to use HTTPS automatically and by default"> <img src="/resources/images/proxy-file-server.svg" alt="Caddy is the only server to use HTTPS automatically and by default">
</div> </div>
@ -151,7 +148,7 @@
<div class="wrapper"> <div class="wrapper">
<div class="actions text-center"> <div class="actions text-center">
<a href="/docs/download" class="big blue button">Download</a> <a href="/download" class="big blue button">Download</a>
<a href="/docs/command-line" class="big gray button">CLI Docs</a> <a href="/docs/command-line" class="big gray button">CLI Docs</a>
</div> </div>
</div> </div>
@ -208,7 +205,7 @@
<div class="wrapper"> <div class="wrapper">
<div class="actions text-center"> <div class="actions text-center">
<a href="/docs/download" class="big blue button">Download</a> <a href="/download" class="big blue button">Download</a>
<a href="/docs/caddyfile" class="big gray button">Caddyfile Docs</a> <a href="/docs/caddyfile" class="big gray button">Caddyfile Docs</a>
</div> </div>
</div> </div>
@ -267,7 +264,7 @@
All changes made through the API are persisted to disk so they can continue to be used after restarts. All changes made through the API are persisted to disk so they can continue to be used after restarts.
</h2> </h2>
<a href="/docs/download" class="big blue button">Download</a> <a href="/download" class="big blue button">Download</a>
<a href="/docs/api" class="big gray button">API Docs</a> <a href="/docs/api" class="big gray button">API Docs</a>
<a href="/docs/getting-started" class="big gray button">Tutorial</a> <a href="/docs/getting-started" class="big gray button">Tutorial</a>
</div> </div>
@ -998,7 +995,7 @@
<div class="wrapper"> <div class="wrapper">
<div class="text-center"> <div class="text-center">
<a href="/docs/download" class="big blue button">Download</a> <a href="/download" class="big blue button">Download</a>
<a href="/docs/" class="big gray button">Documentation</a> <a href="/docs/" class="big gray button">Documentation</a>
<a href="https://caddy.community" class="big gray button">Forum</a> <a href="https://caddy.community" class="big gray button">Forum</a>
</div> </div>

View file

@ -0,0 +1,289 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
min-height: 100%;
}
html {
/* by setting the min-height of both html and body to 100%,
it ensures that flex items are centered on screen, but
also allows body to overflow screen height for tall content */
height: 100%;
}
body {
font: 16px sans-serif;
-webkit-font-smoothing: antialiased;
background: #e8ebf0;
display: flex;
}
a {
color: #2b9cff;
text-decoration: none;
}
a:hover {
color: #0f6ab9;
}
.card {
background: white;
margin: auto;
box-shadow: 0 20px 40px rgba(0, 0, 0, .1);
display: flex;
border-radius: 5px;
width: 100%;
max-width: 800px;
}
.card section {
padding: 50px;
text-align: center;
flex-grow: 1;
}
.card section.head {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
flex-grow: 0;
background: #f3f7ff;
border-right: 1px solid #e8ebf0;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.card p {
margin: 0 auto;
max-width: 400px;
line-height: 1.25em;
font-size: 14px;
}
.card .logo {
width: 100%;
max-width: 100px;
display: block;
}
.card h1 {
font-size: 42px;
margin-bottom: 10px;
}
.form-fields {
padding: 20px 0;
}
input {
font-size: 16px;
font-family: 'PT Mono', 'Source Code Pro', monospace;
}
.card input,
.card button {
display: block;
margin: 1em auto;
padding: 8px;
}
.card input[type=text],
.card input[type=email],
.card input[type=password] {
width: 100%;
max-width: 400px;
}
.card button {
font-size: 16px;
font-weight: bold;
padding: 10px 20px;
}
@media (max-width: 800px) {
.card {
flex-direction: column;
}
}
.swal-content p {
margin: .5em 0;
}
#reset-password-step2 {
display: none;
}
.logo-container {
text-align: center;
margin: 20px auto;
}
.logo {
max-width: 100px;
}
.help {
border-bottom: 1px dotted #222;
cursor: help;
}
.beta {
font-size: 12px;
}
.container {
display: flex;
flex-grow: 1;
justify-content: space-between;
font-family: Maven Pro, sans-serif;
}
.container > nav {
background: #f8faff;
width: 25%;
max-width: 250px;
}
.container > nav ul {
list-style: none;
}
.container > nav ul a {
display: block;
padding: 10px 20px;
color: #546c75;
}
.container > nav ul a:hover {
color: #01324b;
background-color: #ebf3fb;
}
.container > nav ul a.current {
background-color: #e0ecfb;
font-weight: bold;
color: #01324b;
}
.container > main {
display: flex;
flex: 1;
align-items: center;
justify-content: center;
}
.container > main.dashboard {
align-items: flex-start;
justify-content: flex-start;
}
.container section {
background: white;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, .08);
margin: 25px;
}
input[type=text],
input[type=email],
input[type=password] {
padding: 8px;
width: 100%;
max-width: 400px;
border: 1px solid #ccc;
}
form .field {
padding: 0 20px 20px;
max-width: 600px;
margin: 0 auto 20px auto;
border-bottom: 1px solid #eee;
}
form label b {
display: block;
margin-bottom: 10px;
}
form .description {
font-size: 14px;
color: #777;
margin-top: 5px;
}
form button,
form input[type=submit] {
font-size: 16px;
margin: 0 auto;
}
input[type=checkbox] {
cursor: pointer;
transform: scale(1.25);
}
section .pad {
margin: 15px 20px;
}
section button:not([type=submit]),
section .button:not([type=submit]) {
font-size: 14px;
padding: 6px 15px;
margin: auto;
}
section h1 {
font-size: 22px;
font-weight: normal;
}
table {
border-collapse: collapse;
}
tr {
border-bottom: 1px solid #ddd;
}
th,
td {
padding: 10px;
}
th {
background-color: #ebf3ff;
text-align: left;
}

View file

@ -0,0 +1,13 @@
input[name=path] {
font-size: 14px;
padding: 4px;
border-radius: 4px;
width: auto;
/* max-width: 450px; */
max-width: none;
}
a.disabled {
color: #aaa;
cursor: not-allowed;
}

View file

@ -12,20 +12,6 @@ body {
-moz-tab-size: 4; -moz-tab-size: 4;
} }
#v1-banner {
display: block;
background: #5c92a4;
color: #fff;
text-align: center;
padding: 10px 20px;
font-size: 14px;
text-decoration: none;
}
#v1-banner:hover {
background: #457a8c;
}
.wrapper { .wrapper {
max-width: 1400px; max-width: 1400px;
margin-left: auto; margin-left: auto;
@ -38,6 +24,14 @@ body {
text-align: center; text-align: center;
} }
.text-right {
text-align: right;
}
.float-right {
float: right;
}
a { a {
color: #0694f1; color: #0694f1;
text-decoration: none; text-decoration: none;
@ -64,8 +58,8 @@ header nav {
header nav > a { header nav > a {
display: inline-block; display: inline-block;
padding-left: 10px; padding-left: 12px;
padding-right: 10px; padding-right: 12px;
text-decoration: none; text-decoration: none;
color: inherit; color: inherit;
} }
@ -116,6 +110,7 @@ header nav .button {
padding-bottom: 2px; padding-bottom: 2px;
} }
button,
.button { .button {
border-radius: 2em; border-radius: 2em;
padding: 10px 20px; padding: 10px 20px;
@ -124,43 +119,54 @@ header nav .button {
transition: all .2s; transition: all .2s;
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-block;
border: 0;
cursor: pointer;
} }
button:hover,
.button:hover { .button:hover {
transform: scale(1.05); transform: scale(1.05);
} }
button:active,
.button:active { .button:active {
transform: translateY(2px); transform: translateY(2px);
} }
button.red,
.button.red { .button.red {
background-color: #d9552b; background-color: #d9552b;
color: white; color: white;
} }
button.red:hover,
.button.red:hover { .button.red:hover {
background-color: #fd511a; background-color: #fd511a;
} }
button.blue,
.button.blue { .button.blue {
background-color: #0082d0; background-color: #0082d0;
color: white; color: white;
} }
button.blue:hover,
.button.blue:hover { .button.blue:hover {
background-color: #00aaff; background-color: #00aaff;
} }
button.gray,
.button.gray { .button.gray {
background-color: #4c6a79; background-color: #4c6a79;
color: white; color: white;
} }
button.gray:hover,
.button.gray:hover { .button.gray:hover {
background-color: #4f8098; background-color: #4f8098;
} }
button.big,
.button.big { .button.big {
font-size: 125%; font-size: 125%;
text-transform: uppercase; text-transform: uppercase;
@ -169,11 +175,24 @@ header nav .button {
margin-right: 20px; margin-right: 20px;
} }
button.disabled,
.button.disabled,
button:disabled,
.button:disabled {
background-color: #aaa !important;
color: white !important;
transform: none !important;
cursor: not-allowed;
}
p button,
p .button { p .button {
font-size: 18px; font-size: 18px;
padding: 12px 30px; padding: 12px 30px;
} }
article a:hover { article a:hover {
text-decoration: underline; text-decoration: underline;
} }

View file

@ -431,6 +431,39 @@ iframe {
margin: 1em 0 2em; margin: 1em 0 2em;
} }
.nonstandard-notice {
font-size: 14px;
max-width: 500px;
margin: 25px auto;
border: 1px solid #ecd200;
background: #fffddf;
border-radius: 5px;
padding: 10px;
color: #886c00;
line-height: 1.4em;
display: none;
}
.nonstandard {
color: rgb(214, 145, 16);
}
.nonstandard-flag {
cursor: help;
font-size: 8px;
line-height: 1em;
padding: 4px 8px;
text-transform: uppercase;
font-weight: bold;
background-color: rgb(238, 167, 34);
color: white;
border-radius: 4px;
white-space: nowrap;
}
@ -515,6 +548,10 @@ article .json a {
padding-bottom: 0; padding-bottom: 0;
} }
#hovercard .nonstandard-flag {
float: right;
}
#hovercard .module-link { #hovercard .module-link {
display: block; display: block;
text-decoration: none; text-decoration: none;

View file

@ -0,0 +1,303 @@
body {
background-color: #f0f6f9;
}
.download-bar {
display: flex;
justify-content: space-between;
background: white;
border-radius: 4px;
box-shadow: 0 3px 6px rgba(0, 0, 0, .1);
font-size: 20px;
margin-top: 20px;
position: sticky; /* uwu 💓 */
top: 0;
z-index: 1;
}
.download-bar > * {
padding: 15px;
display: flex;
align-items: center;
}
#platform {
padding: 5px 15px;
font-size: 16px;
}
#download {
margin: 0;
font-size: 16px;
font-weight: bold;
}
.packages-explanation {
margin: 20px auto;
}
.warning {
margin-left: 1em;
font-size: 12px;
font-weight: bold;
padding: 2px 15px;
border-radius: 1em;
border: 2px solid rgb(255, 201, 0);
color: rgb(206, 151, 0);
}
input:disabled,
select:disabled,
#optional-packages.disabled .optpkg label {
cursor: not-allowed !important;
}
.loader {
display: inline-block;
font-size: 10px;
text-indent: -9999em;
width: 20px;
height: 20px;
border-radius: 50%;
background: #aaa;
background: -moz-linear-gradient(left, #aaa 10%, rgba(255, 255, 255, 0) 42%);
background: -webkit-linear-gradient(left, #aaa 10%, rgba(255, 255, 255, 0) 42%);
background: -o-linear-gradient(left, #aaa 10%, rgba(255, 255, 255, 0) 42%);
background: -ms-linear-gradient(left, #aaa 10%, rgba(255, 255, 255, 0) 42%);
background: linear-gradient(to right, #aaa 10%, rgba(255, 255, 255, 0) 42%);
animation: load3 1.4s infinite linear;
transform: translateZ(0);
vertical-align: middle;
margin-right: .5em;
margin-top: -2px;
}
#signature .loader {
width: 12px;
height: 12px;
}
.loader:before {
width: 50%;
height: 50%;
background: #fff;
border-radius: 100% 0 0 0;
position: absolute;
top: 0;
left: 0;
content: '';
}
.loader:after {
background: #aaa;
width: 75%;
height: 75%;
border-radius: 50%;
content: '';
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
@-webkit-keyframes load3 {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes load3 {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.table-container {
overflow-x: auto;
box-shadow: 0 2px 4px rgba(0, 0, 0, .1);
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
#optional-packages {
width: 100%;
border-spacing: 0;
border-collapse: collapse;
}
/* #optional-packages tr {
height: 1px;
} */
#optional-packages th,
#optional-packages td {
border-bottom: 1px solid #dfeaf0;
}
#optional-packages th:first-child { border-top-left-radius: 8px; }
#optional-packages th:last-child { border-top-right-radius: 8px; }
#optional-packages th {
background: #dfe8ec;
text-align: left;
text-transform: uppercase;
letter-spacing: 2px;
color: #54676f;
font-weight: bold;
font-size: 12px;
margin-bottom: 1em;
border-color: #90a2ac;
}
#optional-packages th:first-child {
padding-left: 4.25em;
}
#optional-packages td {
background: #fff;
height: 1px; /* TODO: works on Chrome, but not Firefox */
/* height: 100%; TODO: works on Firefox, but not Chrome */
/* TODO:
see https://stackoverflow.com/a/34781198/1048862
(could also do tr with height: 1px which gets ignored,
then td with height: inherit; but this effectively the
same as just doing a td with height: 1px.)
I don't like how either Firefox or Chrome handle this
styling (setting the height of the parent shouldn't be
required at all, the browser is rendering a height
regardless!) but I think I lean toward Firefox's as
being more correct; the hack in Firefox is setting a
flexible 100% height on the parent, rather than the hack
in Chrome which is setting a height that is too small
and stretched or ignored anyway.
*/
}
#optional-packages th,
#optional-packages .optpkg td:first-child label,
#optional-packages td:not(:first-child) {
padding: 15px;
}
#optional-packages .optpkg-name {
font-weight: bold;
}
#optional-packages .optpkg input[type=checkbox] {
transform: scale(1.5);
cursor: pointer;
margin-right: 2em;
}
#optional-packages .optpkg label {
display: flex;
align-items: center;
height: 100%;
line-height: 1em;
cursor: pointer;
}
#optional-packages:not(.disabled) .optpkg label:hover {
background: linear-gradient(90deg, rgba(242,248,253,1) 75%, rgba(242,248,253,0) 100%);
}
#optional-packages .optpkg.selected td {
background-color: #f2f8fd;
}
#optional-packages .optpkg input[type=text] {
font-size: 12px;
padding: 6px;
outline: none;
text-align: center;
border: 1px solid #ccc;
border-radius: 4px;
}
#optional-packages .optpkg input[type=text]::placeholder {
font-style: italic;
}
#optional-packages .optpkg-no-modules {
font-size: 12px;
font-style: italic;
color: #555;
}
#optional-packages .optpkg-module {
margin-top: .5em;
margin-bottom: .5em;
}
#optional-packages .optpkg-module .module-name {
font-weight: bold;
font-family: 'PT Mono', monospace;
}
#optional-packages .optpkg-module .module-description {
color: #444;
margin-left: 1em;
font-size: 14px;
}
.swal-custom-content {
text-align: left;
}
.swal-custom-content ol {
margin: 1em 0 1em 2em;
}
.swal-custom-content li {
margin-bottom: 10px;
}
@media (max-width: 860px) {
.download-bar {
flex-direction: column;
align-items: center;
}
}
@media (max-width: 600px) {
.download-bar {
font-size: inherit;
}
.download-bar > * {
padding: 5px;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View file

@ -0,0 +1,63 @@
if (!loggedIn()
&& window.location.pathname != '/account/login'
&& window.location.pathname != '/account/create'
&& window.location.pathname != '/account/verify'
&& window.location.pathname != '/account/reset-password') {
window.location = '/account/login?redir='+encodeURIComponent(window.location);
}
$(function() {
// highlight current page in left nav
var $currentPageLink = $('.container > nav a[href="'+window.location.pathname+'"]');
$currentPageLink.addClass('current');
// shortcut any logout links to make the POST directly
$('a[href="/account/logout"]').click(function() {
logout();
return false;
});
});
function loggedIn() {
return document.cookie.indexOf('user=') > -1;
}
function logout() {
$.post('/api/logout').done(function() {
window.location = '/';
}).fail(function(jqxhr, status, error) {
document.cookie = 'user=; Path=/; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
swal({
icon: "error",
title: error,
content: errorContent(jqxhr)
}).then(function() {
window.location = '/account/'
});
});
}
function errorContent(jqxhr) {
var div = document.createElement('div');
var p1 = document.createElement('p');
p1.appendChild(document.createTextNode("Sorry, something went wrong:"));
div.appendChild(p1);
var p2 = document.createElement('p');
var p2b = document.createElement('b');
p2b.appendChild(document.createTextNode(jqxhr.responseJSON ? jqxhr.responseJSON.error.message : jqxhr.status + " " + jqxhr.statusText));
p2.appendChild(p2b)
div.appendChild(p2);
if (jqxhr.responseJSON) {
var p3 = document.createElement('p');
p3.appendChild(document.createTextNode("Please include this error ID if reporting:"));
p3.appendChild(document.createElement('br'));
p3.appendChild(document.createTextNode(jqxhr.responseJSON.error.id));
div.appendChild(p3);
}
return div;
}

View file

@ -0,0 +1,28 @@
if (loggedIn()) window.location = '/account/';
$(function() {
$('form input').first().focus();
$('form').submit(function(event) {
$('#submit').prop('disabled', true);
$.post($(this).prop("action"), $(this).serialize()).done(function() {
swal({
icon: "success",
title: "Check your email",
text: "We've sent you an email with a link that expires in 48 hours. Please verify your account before you can use it."
}).then(function() {
window.location = '/account/verify';
});
}).fail(function(jqxhr, status, error) {
swal({
icon: "error",
titleText: "Error",
content: errorContent(jqxhr)
});
$('#submit').prop('disabled', false);
});
return false;
});
});

View file

@ -0,0 +1,125 @@
// download package list as soon as possible
$.get("/api/user-packages").done(function(json) {
var packageList = json.result;
// wait until the DOM has finished loading before rendering the results
$(function() {
// trying out this fancy new syntax:
// https://twitter.com/joshmanders/status/1282395540970496001
packageList.forEach(pkg => {
var $tdPath = $('<td><input type="text" name="path" maxlength="255"></td>');
var $tdListed = $('<td class="text-center"><input type="checkbox" name="listed"></td>');
var $tdAvail = $('<td class="text-center"><input type="checkbox" name="available"></td>');
var $tdDownloads = $('<td>');
var $tdLinks = $('<td><a href="javascript:" class="rescan-package">Rescan</a> &nbsp; <a href="javascript:" class="delete-package">Delete</a></td>');
if (pkg.listed) {
$('input', $tdListed).prop('checked', true);
}
if (pkg.available) {
$('input', $tdAvail).prop('checked', true);
}
var $pathInput = $('input', $tdPath);
$pathInput.val(pkg.path).attr('size', pkg.path.length);
var $tr = $('<tr data-package-id="'+pkg.id+'"></tr>');
$tr.append($tdPath)
.append($tdListed)
.append($tdAvail)
.append($tdDownloads)
.append($tdLinks);
$('#user-packages').append($tr);
// scroll package paths to the left so if they get
// cut off, the leaf package name is still visible
$pathInput.scrollLeft($pathInput.width());
});
});
});
$(function() {
// update packages when fields change
$('#user-packages').on('change', 'input', function() {
$tr = $(this).closest('tr');
$('input', $tr).prop('disabled', true);
$.post('/api/update-package', {
id: $tr.data('package-id'),
listed: $('[name=listed]', $tr).prop('checked') ? 1 : 0,
available: $('[name=available]', $tr).prop('checked') ? 1 : 0,
path: $('[name=path]', $tr).val()
}).fail(function(jqxhr, status, error) {
swal({
icon: "error",
title: "Could not save changes",
content: errorContent(jqxhr)
});
}).always(function() {
$('input', $tr).prop('disabled', false);
});
});
// rescan package
$('#user-packages').on('click', '.rescan-package', function() {
if ($(this).hasClass('disabled')) return;
$tr = $(this).closest('tr');
$('a', $tr).addClass('disabled');
$.post('/api/rescan-package', {
package_id: $tr.data('package-id')
}).done(function(jqxhr, status, error) {
swal({
icon: "success",
title: "Rescan Complete",
text: "Package has been re-scanned and its documentation has been updated."
});
}).fail(function(jqxhr, status, error) {
swal({
icon: "error",
title: "Rescan failed",
content: errorContent(jqxhr)
});
}).always(function() {
$('a', $tr).removeClass('disabled');
});
});
// delete package
$('#user-packages').on('click', '.delete-package', function() {
if ($(this).hasClass('disabled')) return;
swal({
title: "Delete package?",
text: "Deleting the package will remove it from our website.",
icon: "warning",
buttons: true,
dangerMode: true,
}).then((willDelete) => {
// abort if user cancelled
if (!willDelete) return;
$tr = $(this).closest('tr');
$('input', $tr).prop('disabled', true);
$.post('/api/delete-package', {
id: $tr.data('package-id')
}).done(function(jqxhr, status, error) {
$tr.remove();
swal({
icon: "success",
title: "Package deleted"
});
}).fail(function(jqxhr, status, error) {
swal({
icon: "error",
title: "Delete failed",
content: errorContent(jqxhr)
});
}).always(function() {
$('input', $tr).prop('disabled', false);
});
});
});
});

View file

@ -0,0 +1,24 @@
if (loggedIn()) window.location = '/account/';
$(function() {
$('form input').first().focus();
$('form').submit(function(event) {
$('#submit').prop('disabled', true);
$.post($(this).prop("action"), $(this).serialize()).done(function() {
var qsParams = new URLSearchParams(window.location.search);
var destination = qsParams.get('redir');
window.location = destination ? destination : '/account/';
}).fail(function(jqxhr, msg, error) {
swal({
icon: "error",
title: "Bad credentials",
content: errorContent(jqxhr)
});
$('#submit').prop('disabled', false);
});
return false;
});
});

View file

@ -0,0 +1 @@
logout();

View file

@ -0,0 +1,27 @@
$(function() {
$('form input').first().focus();
$('form').submit(function(event) {
$('#submit').prop('disabled', true);
$.post($(this).prop("action"), $(this).serialize()).done(function() {
swal({
icon: "success",
title: "It's yours",
text: "Package claimed. Its documentation is now available on our website and you are responsible for maintaining it. Thank you!"
}).then(function() {
// TODO: ...
// window.location = "/account/login";
});
}).fail(function(jqxhr, status, error) {
swal({
icon: "error",
title: error,
content: errorContent(jqxhr)
});
$('#submit').prop('disabled', false);
});
return false;
});
});

View file

@ -0,0 +1,80 @@
if (loggedIn()) window.location = '/account/';
$(function() {
var qsParams = new URLSearchParams(window.location.search);
var email = qsParams.get("email");
var token = qsParams.get("token");
$('input[name=email]').val(email);
$('input[name=token]').val(token);
if (email && token) showStep2();
$('form input:visible').first().focus();
$('#reset-password-step1').submit(function(event) {
$('button').prop('disabled', false);
$.post($(this).prop("action"), $(this).serialize()).done(function() {
swal({
icon: "info",
title: "Check your email",
text: "If we have an account with that email address, we just sent you some instructions."
}).then(function() {
window.location = '/';
});
}).fail(function(jqxhr, status, error) {
swal({
icon: "error",
title: error,
content: errorContent(jqxhr)
});
$('button').prop('disabled', false);
});
return false;
});
$('#reset-password-step2').submit(function(event) {
$('button').prop('disabled', false);
$.post($(this).prop("action"), $(this).serialize()).done(function() {
swal({
icon: "success",
title: "Reset completed",
text: "You may now log in with your new password."
}).then(function() {
window.location = '/account/login';
});
}).fail(function(jqxhr, status, error) {
swal({
icon: "error",
title: "Error",
content: errorContent(jqxhr)
});
$('button').prop('disabled', false);
});
return false;
});
$('#goto-step1').click(function(event) {
$('#reset-password-step2').hide('fast');
$('#reset-password-step1').show('fast', function() {
$('input:visible').first().focus();
});
return false;
});
$('#goto-step2').click(function(event) {
showStep2();
return false;
});
});
function showStep2() {
$('#reset-password-step1').hide('fast');
$('#reset-password-step2').show('fast', function() {
if ($('input[name=token]').val() != "")
$('input[name=password]').focus();
else
$('input:visible').first().focus();
});
}

View file

@ -0,0 +1,36 @@
if (loggedIn()) window.location = '/account/';
$(function() {
$('form input').first().focus();
$('form').submit(function(event) {
$('#submit').prop('disabled', true);
$.post($(this).prop("action"), $(this).serialize()).done(function() {
swal({
icon: "success",
title: "Account confirmed",
text: "Thank you. You may now log in and use your account!"
}).then(function() {
window.location = "/account/login";
});
}).fail(function(jqxhr, status, error) {
swal({
icon: "error",
title: error,
content: errorContent(jqxhr)
});
$('#submit').prop('disabled', false);
});
return false;
});
// if info is in the query string, fill use and submit it
var qsParams = new URLSearchParams(window.location.search);
var email = qsParams.get("email");
var acct = qsParams.get("code");
$('input[name=email]').val(email);
$('input[name=account_id]').val(acct);
if (email && acct) $('form').submit();
});

View file

@ -7,3 +7,27 @@ document.addEventListener('DOMContentLoaded', function() {
debug: false // Set debug to true if you want to inspect the dropdown debug: false // Set debug to true if you want to inspect the dropdown
}); });
}); });
const caddyImportPath = 'github.com/caddyserver/caddy/v2';
function isStandard(packagePath) {
return packagePath.startsWith(caddyImportPath);
}
function substrBeforeLastDot(s) {
return s.substr(0, s.lastIndexOf('.'))
}
function substrAfterLastDot(s) {
return s.substr(s.lastIndexOf('.'))
}
function truncate(str, len) {
if (!str) return "";
var startLen = str.length;
str = str.substring(0, len);
if (startLen > len) {
str += "...";
}
return str;
}

View file

@ -4,6 +4,8 @@ var pageData = {}, pageDocs = {};
var $renderbox, $hovercard; var $renderbox, $hovercard;
const nonStandardFlag = '<span class="nonstandard-flag" title="This module does not come with official Caddy distributions by default; it needs to be added to custom Caddy builds.">Non-standard</span>';
$(function() { $(function() {
$renderbox = $('#renderbox'); $renderbox = $('#renderbox');
$hovercard = $('#hovercard'); $hovercard = $('#hovercard');
@ -61,7 +63,12 @@ $(function() {
for (var i = 0; i < pageData.namespaces[modNamespace].length; i++) { for (var i = 0; i < pageData.namespaces[modNamespace].length; i++) {
var modInfo = pageData.namespaces[modNamespace][i]; var modInfo = pageData.namespaces[modNamespace][i];
var href = canTraverse() ? '.'+elemPath+'/'+modInfo.name+'/' : './'+modNamespace+'.'+modInfo.name; var href = canTraverse() ? '.'+elemPath+'/'+modInfo.name+'/' : './'+modNamespace+'.'+modInfo.name;
$list.append('<a href="'+href+'" class="module-link">'+modInfo.name+'<span class="module-link-description">'+truncate(modInfo.docs, 115)+'</span></a>'); var content = '<a href="'+href+'" class="module-link"> '+modInfo.name;
if (!isStandard(modInfo.package)) {
content += nonStandardFlag;
}
content += '<span class="module-link-description">'+truncate(modInfo.docs, 115)+'</span></a>';
$list.append(content);
} }
} }
$('#hovercard-module-list').html($list); $('#hovercard-module-list').html($list);
@ -88,7 +95,7 @@ $(function() {
case "struct": case "struct":
for (var j = 0; j < bcVal.struct_fields.length; j++) { for (var j = 0; j < bcVal.struct_fields.length; j++) {
var sf = bcVal.struct_fields[j]; var sf = bcVal.struct_fields[j];
bcSiblings.push({name: sf.key, path: siblingPath}) bcSiblings.push({name: sf.key, path: siblingPath, isStandard: isStandard(bcVal.type_name)})
} }
break; break;
@ -96,7 +103,7 @@ $(function() {
case "module_map": case "module_map":
for (var j = 0; j < pageData.namespaces[bcVal.module_namespace].length; j++) { for (var j = 0; j < pageData.namespaces[bcVal.module_namespace].length; j++) {
var mod = pageData.namespaces[bcVal.module_namespace][j]; var mod = pageData.namespaces[bcVal.module_namespace][j];
bcSiblings.push({name: mod.name, path: siblingPath}) bcSiblings.push({name: mod.name, path: siblingPath, isStandard: isStandard(mod.package)})
} }
} }
@ -108,7 +115,12 @@ $(function() {
sibPath += "/"; sibPath += "/";
} }
sibPath += sib.name+"/"; sibPath += sib.name+"/";
$siblings.append('<a href="'+jsonDocsPathPrefix+sibPath+'">'+sib.name+'</a>'); var aTag = '<a href="'+jsonDocsPathPrefix+sibPath+'"';
if (!sib.isStandard) {
aTag += ' class="nonstandard" title="Non-standard module"';
}
aTag += '>'+sib.name+'</a>';
$siblings.append(aTag);
} }
$('#hovercard-breadcrumb-siblings').html($siblings).show(); $('#hovercard-breadcrumb-siblings').html($siblings).show();
@ -147,6 +159,14 @@ function beginRendering(json) {
pageData = json; pageData = json;
console.log("DATA:", pageData); console.log("DATA:", pageData);
// show notice if module is non-standard
if (!isStandard(pageData.structure.type_name)) {
var projectHref = 'https://'+pageData.structure.type_name;
projectHref = substrBeforeLastDot(projectHref);
$('.nonstandard-project-link').attr('href', projectHref).text(projectHref);
$('.nonstandard-notice').prepend(nonStandardFlag).show();
}
if (pageData.structure.doc) { if (pageData.structure.doc) {
// for most types, just render their docs // for most types, just render their docs
$('#top-doc').html(markdown(pageData.structure.doc)); $('#top-doc').html(markdown(pageData.structure.doc));
@ -308,16 +328,6 @@ function indent(nesting, $group) {
$group.append($span); $group.append($span);
} }
function truncate(str, len) {
if (!str) return "";
var startLen = str.length;
str = str.substring(0, len);
if (startLen > len) {
str += "...";
}
return str;
}
function makeSubmoduleList(path, value) { function makeSubmoduleList(path, value) {
while (value.elems) { while (value.elems) {
value = value.elems; value = value.elems;
@ -330,7 +340,11 @@ function makeSubmoduleList(path, value) {
for (var j = 0; j < pageData.namespaces[value.module_namespace].length; j++) { for (var j = 0; j < pageData.namespaces[value.module_namespace].length; j++) {
var submod = pageData.namespaces[value.module_namespace][j]; var submod = pageData.namespaces[value.module_namespace][j];
var href = canTraverse() ? '.'+path+'/'+submod.name+'/' : './'+value.module_namespace+'.'+submod.name; var href = canTraverse() ? '.'+path+'/'+submod.name+'/' : './'+value.module_namespace+'.'+submod.name;
submodList += '<li><a href="'+href+'">'+submod.name+'</li>'; var submodLink = '<a href="'+href+'">'+submod.name+'</a>';
if (!isStandard(submod.package)) {
submodLink += ' '+nonStandardFlag;
}
submodList += '<li>'+submodLink+'</li>';
} }
} }
submodList += '</ul>'; submodList += '</ul>';

View file

@ -0,0 +1,221 @@
// download package list as soon as possible
$.get("/api/packages").done(function(json) {
var packageList = json.result;
// wait until the DOM has finished loading before rendering the results
$(function() {
const optpkgTemplate =
'<tr class="optpkg">'+
' <td><label><input type="checkbox"><span class="optpkg-name"></span></label></td>'+
' <td class="text-center"><input type="text" name="version" placeholder="latest" title="Package version" size="5"></td>'+
' <td class="optpkg-modules"></td>'+
'</tr>';
const optpkgModuleTemplate =
'<div class="optpkg-module">'+
' <a class="module-name" title="View docs"></a>'+
' <span class="module-description"></span>'+
'</div>';
for (var i = 0; i < packageList.length; i++) {
var pkg = packageList[i];
if (isStandard(pkg.path)) {
// not necessary to show, since these packages
// come with standard distribution
continue;
}
var $optpkg = $(optpkgTemplate);
$('.optpkg-name', $optpkg).text(pkg.path);
if (pkg.modules && pkg.modules.length > 0) {
for (var j = 0; j < pkg.modules.length; j++) {
var mod = pkg.modules[j];
var $mod = $(optpkgModuleTemplate);
$('.module-name', $mod).attr('href', '/docs/modules/'+mod.name).text(mod.name);
$('.module-description', $mod).text(truncate(mod.docs, 120));
$('.optpkg-modules', $optpkg).append($mod);
}
} else {
$('.optpkg-modules', $optpkg)
.addClass("optpkg-no-modules")
.text('This package does not add any modules. Either it is another kind of plugin (such as a config adapter) or this listing is in error.');
}
$('#optional-packages').append($optpkg);
}
});
}).fail(function(jqxhr, status, error) {
swal({
icon: "error",
title: "Unavailable",
content: $('<div>Sorry, the build server is down for maintenance right now. You can try again later or <a href="https://github.com/caddyserver/caddy/releases/latest">download pre-built Caddy binaries from GitHub</a> any time.</div>')[0]
});
$(function() {
disableFields(false);
});
});
$(function() {
autoPlatform();
downloadButtonHtml = $('#download').html();
// update the page, including the download link, when form fields change
$('#optional-packages').on('change', 'input[type=checkbox]', function() {
$(this).closest('.optpkg').toggleClass('selected');
updatePage();
});
$('#optional-packages').on('change keyup', 'input[name=version]', function() {
updatePage();
});
$('#platform').change(function() {
updatePage();
});
$('#download').click(function(event) {
if ($(this).hasClass('disabled')) {
return false;
}
disableFields(true);
fathom.trackGoal('U9K2UTFV', 0);
$.ajax($(this).attr('href'), { method: "HEAD" }).done(function(data, status, jqxhr) {
window.onbeforeunload = null; // disable exit confirmation before "redirecting" to download
window.location = jqxhr.getResponseHeader("Location");
}).fail(function(jqxhr, status, error) {
handleBuildError(jqxhr, status, error);
}).always(function() {
enableFields();
});
return false;
});
})
// autoPlatform choooses the platform in the list that best
// matches the user's browser, if it's available.
function autoPlatform() {
// assume 32-bit linux, then change OS and architecture if justified
var os = "linux", arch = "386", arm = "";
// change os
if (/Macintosh/i.test(navigator.userAgent)) {
os = "darwin";
} else if (/Windows/i.test(navigator.userAgent)) {
os = "windows";
} else if (/FreeBSD/i.test(navigator.userAgent)) {
os = "freebsd";
} else if (/OpenBSD/i.test(navigator.userAgent)) {
os = "openbsd";
}
// change architecture
if (os == "darwin" || /amd64|x64|x86_64|Win64|WOW64|i686|64-bit/i.test(navigator.userAgent)) {
arch = "amd64";
} else if (/arm64/.test(navigator.userAgent)) {
arch = "arm64";
} else if (/ ARM| armv/.test(navigator.userAgent)) {
arch = "arm";
}
// change arm version
if (arch == "arm") {
arm = "7"; // assume version 7 by default
if (/armv6/.test(navigator.userAgent)) {
arm = "6";
} else if (/armv5/.test(navigator.userAgent)) {
arm = "5";
}
}
var selString = os+"-"+arch;
if (arm != "") {
selString += "-"+arm;
}
$('#platform').val(selString);
updatePage();
}
function getDownloadLink() {
// get platform components
var platformParts = $('#platform').val().split("-");
var os = platformParts[0];
var arch = platformParts[1];
var arm = platformParts.length > 2 ? platformParts[2] : "";
var qs = new URLSearchParams();
if (os) qs.set("os", os);
if (arch) qs.set("arch", arch);
if (arm) qs.set("arm", arm);
// get plugins and their versions
$('#optional-packages .selected').each(function() {
// get package path
var p = $('.optpkg-name', this).text().trim();
// get package version, if user specified one
var ver = $('input[name=version]', this).val().trim();
if (ver) {
p += "@"+ver;
}
qs.append("p", p);
});
var idempotencyKey = Math.floor(Math.random() * 99999999999999);
qs.append("idempotency", idempotencyKey);
return "/api/download?"+qs.toString();
}
function handleBuildError(jqxhr, status, error) {
var $content = $('<div class="swal-custom-content">');
if (jqxhr.status == 502) {
swal({
icon: "error",
title: "Unavailable",
content: $content.html('Sorry, the build server is down for maintenance right now. You can try again later or <a href="https://github.com/caddyserver/caddy/releases/latest">download pre-built Caddy binaries from GitHub</a>.')[0]
});
} else {
swal({
icon: "error",
title: "Build failed",
content: $content.html('The two most common reasons are:<ol><li><b>A plugin is not compiling.</b> The developer must release a new version that compiles.</li><li><b>The build configuration is invalid.</b> If you specified any versions, make sure they are correct and <a href="https://golang.org/cmd/go/#hdr-Module_compatibility_and_semantic_versioning" target="_blank">within the same major version</a> as the path of the associated package.</li></ol>In the meantime, you can <a href="https://github.com/caddyserver/caddy/releases/latest">download Caddy from GitHub</a> without any plugins.')[0]
});
}
}
function updatePage() {
$('#package-count').text($('.optpkg.selected').length);
$('#download').attr('href', getDownloadLink());
}
function disableFields(building) {
$('#download, #optional-packages').addClass('disabled');
$('.download-bar select, #optional-packages input').prop('disabled', true);
if (building) {
$('#download').html('<div class="loader"></div> Building');
// prevent accidentally leaving the page during a build
window.onbeforeunload = function() {
return "Your custom build is in progress.";
};
} else {
$('#download').html('Builds Unavailable');
}
}
function enableFields() {
$('#download, #optional-packages').removeClass('disabled');
$('.download-bar select, #optional-packages input').prop('disabled', false);
$('#download').html(downloadButtonHtml);
// allow user to leave page easily
window.onbeforeunload = null;
}
var downloadButtonHtml; // to restore button to its original contents

View file

@ -9,7 +9,7 @@ setPageTitle();
$.get("/api/docs/config"+configPath, function(json) { $.get("/api/docs/config"+configPath, function(json) {
// wait until the DOM has finished loading before rendering the results // wait until the DOM has finished loading before rendering the results
$(function() { $(function() {
beginRendering(json); beginRendering(json.result);
// establish the breadcrumb // establish the breadcrumb
var $bc = $('.breadcrumbs'); var $bc = $('.breadcrumbs');

View file

@ -9,21 +9,24 @@ if (moduleID) {
$(function() { $(function() {
$('#module-docs-container').show(); $('#module-docs-container').show();
$('h1').text("Module "+moduleID); $('h1').text("Module "+moduleID);
beginRendering(json); beginRendering(json.result);
}); });
}); });
} else { } else {
// populate the module list // populate the module list
$.get("/api/modules", function(moduleList) { $.get("/api/modules", function(json) {
var moduleList = json.result;
// wait until the DOM has finished loading before rendering the results // wait until the DOM has finished loading before rendering the results
$(function() { $(function() {
$('#module-list-container').show(); $('#module-list-container').show();
$table = $('#module-list'); $table = $('#module-list');
for (modID in moduleList) { for (modID in moduleList) {
var doc = moduleList[modID]; var val = moduleList[modID];
var standard = isStandard(val.type_name);
var $tr = $('<tr/>'); var $tr = $('<tr/>');
$tr.append('<td><a href="./'+modID+'" class="module-link">'+modID+'</a></td>'); $tr.append('<td><a href="./'+modID+'" class="module-link">'+modID+'</a>'+(standard ? '' : ' '+nonStandardFlag)+'</td>');
$tr.append('<td>'+markdown(truncate(doc, 200))+'</td>'); $tr.append('<td>'+markdown(truncate(val.doc, 200))+'</td>');
$table.append($tr); $table.append($tr);
} }
}); });

1
src/resources/js/sweetalert.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -26,7 +26,7 @@
<h2>Still the only web server to use <b>TLS automatically and by default.</b> <b>Deploy and scale HTTPS effortlessly</b> with Caddy 2.</h2> <h2>Still the only web server to use <b>TLS automatically and by default.</b> <b>Deploy and scale HTTPS effortlessly</b> with Caddy 2.</h2>
<div class="action"> <div class="action">
<a href="/docs/download" class="big cyan button">Download</a> <a href="/download" class="big cyan button">Download</a>
<a href="/docs/getting-started" class="big gray button">Get Started</a> <a href="/docs/getting-started" class="big gray button">Get Started</a>
<br> <br>
Caddy uses only the Apache 2.0 open source license. Caddy uses only the Apache 2.0 open source license.
@ -470,7 +470,7 @@ http://localhost {
<br><br> <br><br>
<div class="action"> <div class="action">
<a href="/docs/download" class="big cyan button">Download</a> <a href="/download" class="big cyan button">Download</a>
<a href="/docs/getting-started" class="big gray button">Get Started</a> <a href="/docs/getting-started" class="big gray button">Get Started</a>
</div> </div>
</div> </div>