mirror of
https://github.com/caddyserver/website.git
synced 2025-04-21 12:36:16 -04:00
feat(redesign): synchronize new download page to upstream
This commit is contained in:
parent
839ec63c38
commit
bd4ddf8b58
4 changed files with 624 additions and 49 deletions
|
@ -2,32 +2,33 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Download Caddy</title>
|
<title>Download Caddy</title>
|
||||||
{{import "/old/includes/head.html"}}
|
{{import "/includes/head.html"}}
|
||||||
{{template "head"}}
|
{{template "head" .}}
|
||||||
<link rel="stylesheet" href="/old/resources/css/download.css{{template "cacheBust"}}">
|
<link rel="stylesheet" href="/resources/css/marketing.css{{template "cacheBust"}}">
|
||||||
<script src="/old/resources/js/jquery-3.4.1.min.js"></script>
|
<link rel="stylesheet" href="/resources/css/features.css{{template "cacheBust"}}">
|
||||||
<script src="/old/resources/js/sweetalert.min.js"></script>
|
<link rel="stylesheet" href="/resources/css/download.css{{template "cacheBust"}}">
|
||||||
<script src="/old/resources/js/download.js{{template "cacheBust"}}"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div class="hero">
|
||||||
|
{{include "/includes/header.html" "dark-header"}}
|
||||||
|
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<header>
|
<div class="hero-content">
|
||||||
<div id="logo-container">
|
<h1>
|
||||||
<a href="/"><img src="/old/resources/images/caddy-logo.svg" id="logo" alt="Caddy"></a>
|
Download
|
||||||
<div id="zerossl-project">a <a href="https://zerossl.com"><img src="/old/resources/images/zerossl-logo.svg" id="zerossl-logo"></a> project</div>
|
<div class="subheading">
|
||||||
|
Build your own caddy binary with modules.
|
||||||
</div>
|
</div>
|
||||||
{{include "/old/includes/header-nav.html"}}
|
</h1>
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="notice">
|
|
||||||
⚠️ <b>Due to <a href="https://github.com/golang/go/issues/56494">multiple</a> outstanding <a href="https://github.com/golang/go/issues/53905">bugs</a> in the <code>go</code> command, we are aware that some downloads may hang or fail.</b> In the meantime, you can download Caddy from <b><a href="https://github.com/caddyserver/caddy/releases">the latest release on GitHub</a></b>, or use <b><a href="https://github.com/caddyserver/xcaddy">xcaddy</a></b> for custom builds. (Remember, this download page comes with no guarantees or SLAs.) Sorry for the inconvenience.
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="download-bar">
|
</div>
|
||||||
<div>
|
<main>
|
||||||
<div>
|
<div id="download" class="wrapper">
|
||||||
<b>Platform:</b>
|
<div class="shadow-lg">
|
||||||
<select size="1" id="platform" selected="linux-amd64">
|
<div id="downloader">
|
||||||
|
<span>Download the caddy binary <span id="modules-count"></span> for</span>
|
||||||
|
<select size="1" selected="linux-amd64" id="platform" class="shadow">
|
||||||
<option value="dragonfly-amd64">Dragonfly amd64</option>
|
<option value="dragonfly-amd64">Dragonfly amd64</option>
|
||||||
<option value="freebsd-amd64">FreeBSD amd64</option>
|
<option value="freebsd-amd64">FreeBSD amd64</option>
|
||||||
<option value="freebsd-arm-6">FreeBSD arm 6</option>
|
<option value="freebsd-arm-6">FreeBSD arm 6</option>
|
||||||
|
@ -56,39 +57,61 @@
|
||||||
<option value="windows-arm-7">Windows arm 7</option>
|
<option value="windows-arm-7">Windows arm 7</option>
|
||||||
<option value="windows-arm64">Windows arm64</option>
|
<option value="windows-arm64">Windows arm64</option>
|
||||||
</select>
|
</select>
|
||||||
|
<a id="download-link" href="/api/download">
|
||||||
|
<button class="primary">
|
||||||
|
Download
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="command" onclick="copyCommand()">
|
||||||
|
<pre>
|
||||||
|
<span id="command-builder">xcaddy build</span>
|
||||||
|
</pre>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-copy" width="24"
|
||||||
|
height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
|
||||||
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||||
|
<path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path>
|
||||||
|
<path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path>
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<b>Standard features:</b> <span title="All official Caddy builds come with standard plugins">☑️</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<b>Extra features:</b> <span id="package-count">0</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<a href="/api/download" class="blue button" id="download">Download</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input type="search" id="filter" placeholder="Filter packages and modules...">
|
<div class="wrapper filters">
|
||||||
|
<input id="search-package" placeholder="Search package: e.g. cloudflare" class="shadow" />
|
||||||
<div class="text-center">
|
<select id="sort-package" class="shadow">
|
||||||
<span class="warning">⚠️ Only choose plugins you need and trust</span>
|
<option value="download">Sort by most popular</option>
|
||||||
</div>
|
<option value="alphabetically">Sort alphabetically</option>
|
||||||
<div class="text-center" id="darwin-warning">
|
<option value="type">Group by module namespace</option>
|
||||||
<span class="warning">⚠️ Run the following against the downloaded binary:
|
</select>
|
||||||
<code>xattr -d com.apple.quarantine </code>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="optional-packages">
|
<div class="wrapper list">
|
||||||
<!-- Populated by JavaScript -->
|
<div id="side-panel-packages">
|
||||||
|
</div>
|
||||||
|
<div id="packages">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
{{include "/old/includes/footer.html"}}
|
{{include "/includes/footer.html"}}
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
let groupBy = 'download';
|
||||||
|
const getCardTemplate = item => `{{ include "/includes/card.html" }}`;
|
||||||
|
const modulesCount = document.getElementById('modules-count');
|
||||||
|
|
||||||
|
document.getElementById('search-package').addEventListener('input', ({ target: { value } }) => {
|
||||||
|
packageManager.setFilterValue(value.toLowerCase());
|
||||||
|
renderList(packageManager.group(groupBy))
|
||||||
|
})
|
||||||
|
document.getElementById('sort-package').addEventListener('change', ({ target: { value } }) => {
|
||||||
|
groupBy = value;
|
||||||
|
renderList(packageManager.group(value))
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<script src="/resources/js/download.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
48
src/includes/card.html
Normal file
48
src/includes/card.html
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<div class="card shadow">
|
||||||
|
<div class="card-header flex">
|
||||||
|
<div class="card-title-name">
|
||||||
|
<h3>
|
||||||
|
${item.name}
|
||||||
|
</h3>
|
||||||
|
<a href="${item.repo}" target="_blank" rel="noopener noreferer">
|
||||||
|
${item.path}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="card-title-info">
|
||||||
|
<span>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-download" width="24"
|
||||||
|
height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
|
||||||
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||||
|
<path d="M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-2"></path>
|
||||||
|
<path d="M7 11l5 5l5 -5"></path>
|
||||||
|
<path d="M12 4l0 12"></path>
|
||||||
|
</svg>
|
||||||
|
${item.downloads}
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-git-commit" width="24"
|
||||||
|
height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
|
||||||
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||||
|
<path d="M12 12m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0"></path>
|
||||||
|
<path d="M12 3l0 6"></path>
|
||||||
|
<path d="M12 15l0 6"></path>
|
||||||
|
</svg>
|
||||||
|
<input class="package-version" placeholder="latest"
|
||||||
|
value="${item.state && item.state !== 'latest' ? item.state : ''}"
|
||||||
|
oninput="updateVersion(event, '${item.path}')" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-description">
|
||||||
|
<p>
|
||||||
|
${item.description}
|
||||||
|
</p>
|
||||||
|
<div class="card-actions">
|
||||||
|
<button type="button" class="button card-button" data-module="${item.path}" onclick="togglePackage(event)">
|
||||||
|
${item.state ? 'Remove' : 'Add'} this module
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
298
src/resources/css/download.css
Normal file
298
src/resources/css/download.css
Normal file
|
@ -0,0 +1,298 @@
|
||||||
|
* {
|
||||||
|
--border-download: 1px solid rgba(226, 232, 240, 0.8);
|
||||||
|
--radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
border: var(--border-download);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 16px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: var(--body-bg);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shadow {
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .1), 0 1px 2px 0 rgba(0, 0, 0, .06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.shadow-lg {
|
||||||
|
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper.list {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#side-panel-packages {
|
||||||
|
padding-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#side-panel-packages>div {
|
||||||
|
padding: 32px 1rem 1rem 0;
|
||||||
|
overflow-y: scroll;
|
||||||
|
width: 250px;
|
||||||
|
max-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: sticky;
|
||||||
|
top: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#download-link>button {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#platform {
|
||||||
|
width: unset;
|
||||||
|
min-height: unset;
|
||||||
|
height: unset;
|
||||||
|
line-height: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
#packages {
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 32px;
|
||||||
|
padding-bottom: 32px;
|
||||||
|
display: grid;
|
||||||
|
gap: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#download {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
padding-bottom: 32px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
#download>div {
|
||||||
|
border: var(--border-download);
|
||||||
|
background-color: var(--body-bg);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#download>div {
|
||||||
|
border: var(--border-download);
|
||||||
|
background-color: var(--body-bg);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#downloader>button {
|
||||||
|
margin: 0 auto;
|
||||||
|
min-width: fit-content;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 80%;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#downloader {
|
||||||
|
padding-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#command {
|
||||||
|
border-radius: var(--radius);
|
||||||
|
border: 1px solid var(--button-border-color);
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
display: inline-flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#command>pre {
|
||||||
|
width: 100%;
|
||||||
|
overflow-x: scroll;
|
||||||
|
display: inline-flex;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#command>svg {
|
||||||
|
height: 1em;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#command-builder::before {
|
||||||
|
content: '$';
|
||||||
|
color: var(--text-color-muted);
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
padding-bottom: 16px;
|
||||||
|
color: rgb(14, 110, 189);
|
||||||
|
border-color: rgb(14, 110, 189);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
padding-left: 16px;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title-name {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-weight: lighter;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title-name>a {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title-info {
|
||||||
|
display: inline-flex;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 90%;
|
||||||
|
color: var(--text-color-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title-info>span>svg {
|
||||||
|
margin-right: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header>:first-child>span:first-child {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-description {
|
||||||
|
display: flex;
|
||||||
|
color: var(--text-color-muted);
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 100%;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-description>p {
|
||||||
|
font-weight: 400;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 4;
|
||||||
|
overflow: hidden;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-actions {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-button {
|
||||||
|
margin: 0 auto;
|
||||||
|
min-width: fit-content;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 80%;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
article {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filters {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 2fr 1fr 2fr;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1400px) {
|
||||||
|
.card-description {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filters {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper.list {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#side-panel-packages>div {
|
||||||
|
overflow: unset;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
select {
|
||||||
|
padding: 0.5rem;
|
||||||
|
height: 3rem;
|
||||||
|
font-size: 100%;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid var(--button-border-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
background-color: var(--body-bg);
|
||||||
|
width: 100%;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filters>div {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
padding-left: 1rem;
|
||||||
|
padding-right: 2.5rem;
|
||||||
|
font-size: .875rem;
|
||||||
|
line-height: 1.25rem;
|
||||||
|
line-height: 2;
|
||||||
|
min-height: 3rem;
|
||||||
|
border: 1px solid var(--button-border-color);
|
||||||
|
background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
|
||||||
|
background-position: calc(100% - 20px) calc(1px + 50%), calc(100% - 16.1px) calc(1px + 50%);
|
||||||
|
background-size: 4px 4px, 4px 4px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package-version {
|
||||||
|
height: 50%;
|
||||||
|
font-size: 80%;
|
||||||
|
width: 4rem;
|
||||||
|
padding-top: unset;
|
||||||
|
padding-bottom: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
padding: unset;
|
||||||
|
background-color: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3.blue {
|
||||||
|
padding-left: unset;
|
||||||
|
border: unset;
|
||||||
|
}
|
206
src/resources/js/download.js
Normal file
206
src/resources/js/download.js
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
const BASE_API_PATH = '/api';
|
||||||
|
const pkgURL = `${BASE_API_PATH}/packages`;
|
||||||
|
const downloadURL = `${BASE_API_PATH}/download`;
|
||||||
|
|
||||||
|
class Package {
|
||||||
|
/**
|
||||||
|
* @typedef {Object} Module
|
||||||
|
* @property {string} docs
|
||||||
|
* @property {string} name
|
||||||
|
* @property {string} package
|
||||||
|
* @property {string} repo
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} Pkg
|
||||||
|
* @property {string} id
|
||||||
|
* @property {string} path
|
||||||
|
* @property {string} published
|
||||||
|
* @property {boolean} listed
|
||||||
|
* @property {boolean} available
|
||||||
|
* @property {number} downloads
|
||||||
|
* @property {ReadonlyArray<Module>} modules
|
||||||
|
* @property {string} repo
|
||||||
|
* @property {string} name
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {ReadonlyArray<Pkg>}
|
||||||
|
*/
|
||||||
|
packages = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
filter = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns Promise<>
|
||||||
|
*/
|
||||||
|
getPackages() {
|
||||||
|
return fetch(pkgURL, { headers: { 'X-Requested-With': 'XMLHttpRequest', Origin: 'https://caddyserver.com' } })
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(({ result }) => this.packages = result.sort((a, b) => a.downloads - b.downloads).map(item => ({
|
||||||
|
...item,
|
||||||
|
description: item.modules?.map(m => m.docs ?? m.name).join('\n') ?? '',
|
||||||
|
name: (item.repo || item.path).split('/').pop().toLowerCase(),
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
setFilterValue(value) {
|
||||||
|
this.filter = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSearchPackages(pkgs) {
|
||||||
|
if (!this.filter) {
|
||||||
|
return pkgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgs.filter(pkg => pkg.name.includes(this.filter) || pkg.repo.includes(this.filter) || pkg.description.includes(this.filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {'alphabetically' | 'type' | 'download'} groupBy
|
||||||
|
* @return {
|
||||||
|
* Record<string, Pkg> | ReadonlyArray<Pkg}
|
||||||
|
*/
|
||||||
|
group(groupBy = 'alphabetically') {
|
||||||
|
const pkgs = this.getSearchPackages(this.packages);
|
||||||
|
switch (groupBy) {
|
||||||
|
case 'alphabetically':
|
||||||
|
return pkgs.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
case 'download':
|
||||||
|
return pkgs.sort((a, b) => b.downloads - a.downloads);
|
||||||
|
case 'type':
|
||||||
|
return pkgs.reduce((acc, current) => {
|
||||||
|
if (!current?.modules?.length) {
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
current.modules.forEach(module => {
|
||||||
|
let moduleName = module.name
|
||||||
|
if (module.name.includes('.')) {
|
||||||
|
const splitted = module.name.split('.')
|
||||||
|
moduleName = `${splitted[0]}.${splitted[1]}`
|
||||||
|
}
|
||||||
|
if (acc[moduleName]) {
|
||||||
|
acc[moduleName] = [...acc[moduleName], current];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {
|
||||||
|
"http.handlers": [],
|
||||||
|
"http.matchers": [],
|
||||||
|
"dns.providers": [],
|
||||||
|
"http.encoders": [],
|
||||||
|
"caddy.config_loaders": [],
|
||||||
|
"caddy.fs": [],
|
||||||
|
"caddy.listeners": [],
|
||||||
|
"caddy.logging.encoders": [],
|
||||||
|
"caddy.logging.encoders.filter": [],
|
||||||
|
"caddy.logging.writers": [],
|
||||||
|
"caddy.storage": [],
|
||||||
|
"events.handlers": [],
|
||||||
|
"http.authentication.hashes": [],
|
||||||
|
"http.authentication.providers": [],
|
||||||
|
"http.ip_sources": [],
|
||||||
|
"http.precompressed": [],
|
||||||
|
"http.reverse_proxy.circuit_breakers": [],
|
||||||
|
"http.reverse_proxy.selection_policies": [],
|
||||||
|
"http.reverse_proxy.transport": [],
|
||||||
|
"http.reverse_proxy.upstreams": [],
|
||||||
|
"tls.certificates": [],
|
||||||
|
"tls.client_auth": [],
|
||||||
|
"tls.handshake_match": [],
|
||||||
|
"tls.issuance": [],
|
||||||
|
"tls.get_certificate": [],
|
||||||
|
"tls.stek": [],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const packageManager = new Package();
|
||||||
|
|
||||||
|
const params = new URLSearchParams(window.location.search?.slice(1));
|
||||||
|
let versions = params.getAll('p').reduce((acc, current) => {
|
||||||
|
[p, v] = current.split('@');
|
||||||
|
|
||||||
|
acc[p] = v ?? '';
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
function togglePackage({ target: { dataset: { module } } }) {
|
||||||
|
const element = document.getElementById('packages').querySelector(`button[data-module="${module}"]`);
|
||||||
|
if (module in versions) {
|
||||||
|
delete versions[module];
|
||||||
|
const countVersions = Object.keys(versions).length;
|
||||||
|
if (!countVersions) {
|
||||||
|
modulesCount.innerHTML = '';
|
||||||
|
} else {
|
||||||
|
modulesCount.innerHTML = `with ${countVersions} extra module${countVersions > 1 ? 's' : ''}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
element.innerHTML = "Add this module";
|
||||||
|
} else {
|
||||||
|
versions[module] = '';
|
||||||
|
const countVersions = Object.keys(versions).length;
|
||||||
|
element.innerHTML = "Remove this module";
|
||||||
|
modulesCount.innerHTML = `with ${countVersions} extra module${countVersions > 1 ? 's' : ''}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
setDownloadLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setDownloadLink() {
|
||||||
|
document.getElementById('command-builder').innerText = getCommand();
|
||||||
|
document
|
||||||
|
.getElementById('download-link')
|
||||||
|
.setAttribute('href', `${downloadURL}?${new URLSearchParams(Object.entries(versions).map(([p, v]) => ['p', `${p}${!!v ? `@${v}` : ''}`])).toString()}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCommand() {
|
||||||
|
return `xcaddy build${Object.entries(versions ?? {}).map(([p, v]) => ` --with ${p}${!!v ? `@${v}` : ''}`).join('')}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyCommand() {
|
||||||
|
navigator.clipboard.writeText(getCommand())
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderList(list) {
|
||||||
|
if (groupBy === 'type') {
|
||||||
|
const groupedData = Object.entries(packageManager.group(groupBy)).filter(([_, items]) => !!items.length)
|
||||||
|
document.getElementById('side-panel-packages').innerHTML = `
|
||||||
|
<div>
|
||||||
|
<h3 class="blue">Namespaces</h3>
|
||||||
|
${groupedData.map(([k]) => `<a href="#${k}"> ${k}</a>`).join('')}
|
||||||
|
</div>`;
|
||||||
|
document.getElementById('packages').innerHTML = groupedData.map(([category, items]) => `
|
||||||
|
<section id="${category}">
|
||||||
|
<h2 class="blue">${category}</h2>
|
||||||
|
<div class="card-list">${items.map(item => getCardTemplate({ ...item, state: versions[item.path] })).join('')}</div>
|
||||||
|
</section>`).join('')
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('side-panel-packages').innerHTML = '';
|
||||||
|
document.getElementById('packages').innerHTML = `
|
||||||
|
<div class="card-list">
|
||||||
|
${list.map(item => getCardTemplate({ ...item, state: versions[item.path] })).join('')}
|
||||||
|
</div>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
packageManager.getPackages().then(() => {
|
||||||
|
renderList(packageManager.group(groupBy));
|
||||||
|
const countVersions = Object.keys(versions).length;
|
||||||
|
modulesCount.innerHTML = countVersions ? `with ${countVersions} extra module${countVersions > 1 ? 's' : ''}` : '';
|
||||||
|
setDownloadLink();
|
||||||
|
})
|
||||||
|
|
||||||
|
function updateVersion({ target: { value } }, pkg) {
|
||||||
|
versions[pkg] = value;
|
||||||
|
setDownloadLink();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue