Builds a website
This commit is contained in:
1 parent
4d5dbf26c4
commit
2fb9a402eb
20 files changed
+3424
No files matched your search
+10
@@ -0,0 +1,10 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
Generated
+2715
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "portainer-templates",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^2.0.0",
|
||||
"@sveltejs/kit": "^1.5.0",
|
||||
"sass": "^1.62.0",
|
||||
"svelte": "^3.54.0",
|
||||
"svelte-check": "^3.0.1",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^4.2.0"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,41 @@
|
||||
<script lang="ts">
|
||||
export let categories: string[];
|
||||
export let selectedCategories: string[];
|
||||
export let toggleCategory: (category: string) => void;
|
||||
</script>
|
||||
|
||||
<div class="categories">
|
||||
{#each Object.keys(categories) as category}
|
||||
<span
|
||||
on:click={() => toggleCategory(category)}
|
||||
class:selected="{selectedCategories.includes(category)}"
|
||||
class="cat"
|
||||
>{category}</span>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.categories {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin: 1rem auto;
|
||||
padding: 0 1rem;
|
||||
max-width: var(--max-width);
|
||||
.cat {
|
||||
border: 1px solid transparent;
|
||||
padding: 0 0.3rem;
|
||||
margin: 0.25rem;
|
||||
line-height: 2rem;
|
||||
border-radius: 6px;
|
||||
text-transform: capitalize;
|
||||
background: var(--card);
|
||||
transition: all 0.3s ease-in-out;
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
&:hover, &.selected {
|
||||
background: var(--gradient);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,51 @@
|
||||
<script lang="ts">
|
||||
import Icon from '$lib/Icon.svelte';
|
||||
let footerInfo = {
|
||||
author: 'Alicia Sykes',
|
||||
authorSite: 'https://github.com/lissy93',
|
||||
license: 'MIT',
|
||||
licenseLink: 'https://gist.github.com/Lissy93/143d2ee01ccc5c052a17',
|
||||
copyright: true,
|
||||
source: 'https://github.com/lissy93/portainer-templates',
|
||||
};
|
||||
</script>
|
||||
|
||||
<footer>
|
||||
<p>
|
||||
© <a href={footerInfo.authorSite} target="_blank" rel="noreferrer">{footerInfo.author}</a>
|
||||
{new Date().getFullYear()} - Licensed under
|
||||
<a href={footerInfo.licenseLink} target="_blank" rel="noreferrer">{footerInfo.license}</a> -
|
||||
View on <a href={footerInfo.source} target="_blank" rel="noreferrer">
|
||||
GitHub <Icon name="github" color="var(--accent)" /></a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
<style lang="scss">
|
||||
footer {
|
||||
bottom: 0;
|
||||
padding: 0.5rem 0;
|
||||
width: 100%;
|
||||
background: var(--card);
|
||||
p {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
a {
|
||||
color: var(--accent);
|
||||
border-radius: 4px;
|
||||
padding: 0.1rem 0.25rem;
|
||||
text-decoration: none;
|
||||
display: inline-flex;
|
||||
flex-direction: revert;
|
||||
gap: 0.25rem;
|
||||
align-items: center;
|
||||
&:hover {
|
||||
background: var(--accent);
|
||||
color: var(--background);
|
||||
:global(svg) {
|
||||
fill: var(--background);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,88 @@
|
||||
<script>
|
||||
import Icon from '$lib/Icon.svelte';
|
||||
</script>
|
||||
|
||||
<div class="hero">
|
||||
<header>
|
||||
<h1>Portainer Templates</h1>
|
||||
<p class="sub-title">The largest single collection, of ready-to-go Portainer templates</p>
|
||||
</header>
|
||||
|
||||
<section class="cta">
|
||||
<a href="https://github.com/Lissy93/portainer-templates">
|
||||
<Icon name="github" width="26px" height="26px" />
|
||||
View on GitHub
|
||||
</a>
|
||||
<a href="https://github.com/Lissy93/portainer-templates">
|
||||
<Icon name="portainer" width="26px" height="26px" />
|
||||
Install on Portainer
|
||||
</a>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.hero {
|
||||
padding: 2rem;
|
||||
header {
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 4rem;
|
||||
margin: 0 auto;
|
||||
background: var(--gradient);
|
||||
background-clip: border-box;
|
||||
-moz-background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-moz-text-fill-color: transparent;
|
||||
-webkit-text-fill-color: transparent;
|
||||
color: transparent;
|
||||
}
|
||||
.sub-title {
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
font-size: 1.4rem;
|
||||
font-style: italic;
|
||||
font-weight: 200;
|
||||
}
|
||||
}
|
||||
|
||||
section.cta {
|
||||
margin: 1rem auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
a {
|
||||
font-size: 1.2rem;
|
||||
transition:all 0.3s ease-in-out;
|
||||
position: relative;
|
||||
border-radius: 6px;
|
||||
background: var(--background);
|
||||
background-clip: padding-box;
|
||||
padding: 0.5rem 1rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
min-width: 13rem;
|
||||
color: var(--foreground);
|
||||
text-decoration: none;
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: -4px; bottom: -4px;
|
||||
left: -4px; right: -4px;
|
||||
background: var(--gradient);
|
||||
content: '';
|
||||
z-index: -1;
|
||||
border-radius: 6px;
|
||||
}
|
||||
&:hover {
|
||||
background: var(--gradient);
|
||||
transform: scale(1.03) rotate(-0.6deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,103 @@
|
||||
<script lang="ts">
|
||||
export let name: string; // The name of the icon to display
|
||||
export let width = '16px'; // The width of the icon
|
||||
export let height = '16px'; // The height of the icon
|
||||
export let color = 'currentcolor'; // The color of the icon
|
||||
export let hoverColor = 'currentColor'; // The color of the icon on hover
|
||||
export let focusable = 'false'; // Whether the icon is focusable
|
||||
export let hover = false; // Manually set hover state
|
||||
|
||||
const availableIcons = [
|
||||
'github',
|
||||
'portainer',
|
||||
'stack',
|
||||
'container',
|
||||
'swarm',
|
||||
'linux',
|
||||
'windows',
|
||||
'unknown',
|
||||
] as const;
|
||||
|
||||
interface Icon {
|
||||
box: number;
|
||||
name: typeof availableIcons[number];
|
||||
svg: string;
|
||||
}
|
||||
|
||||
let icons: Icon[] = [
|
||||
{
|
||||
box: 500,
|
||||
name: 'github',
|
||||
svg: '<path d="M186.1 328.7c0 20.9-10.9 55.1-36.7 55.1s-36.7-34.2-36.7-55.1 10.9-55.1 36.7-55.1 36.7 34.2 36.7 55.1zM480 278.2c0 31.9-3.2 65.7-17.5 95-37.9 76.6-142.1 74.8-216.7 74.8-75.8 0-186.2 2.7-225.6-74.8-14.6-29-20.2-63.1-20.2-95 0-41.9 13.9-81.5 41.5-113.6-5.2-15.8-7.7-32.4-7.7-48.8 0-21.5 4.9-32.3 14.6-51.8 45.3 0 74.3 9 108.8 36 29-6.9 58.8-10 88.7-10 27 0 54.2 2.9 80.4 9.2 34-26.7 63-35.2 107.8-35.2 9.8 19.5 14.6 30.3 14.6 51.8 0 16.4-2.6 32.7-7.7 48.2 27.5 32.4 39 72.3 39 114.2zm-64.3 50.5c0-43.9-26.7-82.6-73.5-82.6-18.9 0-37 3.4-56 6-14.9 2.3-29.8 3.2-45.1 3.2-15.2 0-30.1-.9-45.1-3.2-18.7-2.6-37-6-56-6-46.8 0-73.5 38.7-73.5 82.6 0 87.8 80.4 101.3 150.4 101.3h48.2c70.3 0 150.6-13.4 150.6-101.3zm-82.6-55.1c-25.8 0-36.7 34.2-36.7 55.1s10.9 55.1 36.7 55.1 36.7-34.2 36.7-55.1-10.9-55.1-36.7-55.1z"/>',
|
||||
},
|
||||
{
|
||||
box: 20,
|
||||
name: 'portainer',
|
||||
svg: '<path d="M12.504 0v1.023l-.01-.015-6.106 3.526H3.417v.751h5.359v3.638h1.942V5.284h1.786v10.416c.027 0 .54-.01.751.091V5.285h.531v10.608c.293.147.55.312.751.54V5.286h6.046v-.75h-1.267l-6.061-3.5V0zm0 1.87v2.664H7.889zm.751.031l4.56 2.633h-4.56zM9.142 5.285h1.21v1.686h-1.21zm-4.736 2.73v1.951h1.942v-1.95zm2.19 0v1.951h1.941v-1.95zm-2.19 2.171v1.951h1.942v-1.95zm2.19 0v1.951h1.941v-1.95zm2.18 0v1.951h1.942v-1.95zM4.36 12.43a3.73 3.73 0 00-.494 1.851c0 1.227.604 2.308 1.52 2.986.239-.064.477-.1.724-.11.1 0 .165.01.266.019.284-1.191 1.383-1.988 2.665-1.988.724 0 1.438.201 1.924.668.229-.476.302-1.007.302-1.575 0-.65-.165-1.292-.494-1.85zm4.828 3.16c-1.21 0-2.226.844-2.492 1.97a.922.922 0 00-.275-.009 2.559 2.559 0 00-2.564 2.556 2.565 2.565 0 003.096 2.5A2.579 2.579 0 009.233 24c.862 0 1.622-.43 2.09-1.081a2.557 2.557 0 004.186-1.97c0-.567-.193-1.099-.504-1.52a2.557 2.557 0 00-3.866-2.94 2.574 2.574 0 00-1.951-.898z"/>',
|
||||
},
|
||||
{
|
||||
box: 500,
|
||||
name: 'stack',
|
||||
svg: '<path d="M264.5 5.2c14.9-6.9 32.1-6.9 47 0l218.6 101c8.5 3.9 13.9 12.4 13.9 21.8s-5.4 17.9-13.9 21.8l-218.6 101c-14.9 6.9-32.1 6.9-47 0L45.9 149.8C37.4 145.8 32 137.3 32 128s5.4-17.9 13.9-21.8L264.5 5.2zM476.9 209.6l53.2 24.6c8.5 3.9 13.9 12.4 13.9 21.8s-5.4 17.9-13.9 21.8l-218.6 101c-14.9 6.9-32.1 6.9-47 0L45.9 277.8C37.4 273.8 32 265.3 32 256s5.4-17.9 13.9-21.8l53.2-24.6 152 70.2c23.4 10.8 50.4 10.8 73.8 0l152-70.2zm-152 198.2l152-70.2 53.2 24.6c8.5 3.9 13.9 12.4 13.9 21.8s-5.4 17.9-13.9 21.8l-218.6 101c-14.9 6.9-32.1 6.9-47 0L45.9 405.8C37.4 401.8 32 393.3 32 384s5.4-17.9 13.9-21.8l53.2-24.6 152 70.2c23.4 10.8 50.4 10.8 73.8 0z"/>',
|
||||
},
|
||||
{
|
||||
box: 500,
|
||||
name: 'container',
|
||||
svg: '<path d="M32 32C14.3 32 0 46.3 0 64S14.3 96 32 96V416c-17.7 0-32 14.3-32 32s14.3 32 32 32H608c17.7 0 32-14.3 32-32s-14.3-32-32-32V96c17.7 0 32-14.3 32-32s-14.3-32-32-32H32zM176 152V360c0 13.3-10.7 24-24 24s-24-10.7-24-24V152c0-13.3 10.7-24 24-24s24 10.7 24 24zm112 0V360c0 13.3-10.7 24-24 24s-24-10.7-24-24V152c0-13.3 10.7-24 24-24s24 10.7 24 24zm112 0V360c0 13.3-10.7 24-24 24s-24-10.7-24-24V152c0-13.3 10.7-24 24-24s24 10.7 24 24zm112 0V360c0 13.3-10.7 24-24 24s-24-10.7-24-24V152c0-13.3 10.7-24 24-24s24 10.7 24 24z"/>',
|
||||
},
|
||||
{
|
||||
box: 500,
|
||||
name: 'swarm',
|
||||
svg: '<path d="M240 80v32h32V80H240zM224 32h64c17.7 0 32 14.3 32 32v64c0 17.7-14.3 32-32 32H224c-17.7 0-32-14.3-32-32V64c0-17.7 14.3-32 32-32zM136.5 268.2l27.7-16-16-27.7-27.7 16 16 27.7zM71 250.7c-8.8-15.3-3.6-34.9 11.7-43.7l55.4-32c15.3-8.8 34.9-3.6 43.7 11.7l32 55.4c8.8 15.3 3.6 34.9-11.7 43.7l-55.4 32c-15.3 8.8-34.9 3.6-43.7-11.7L71 250.7zM304 272h32V240H304v32zm-48-48c0-17.7 14.3-32 32-32h64c17.7 0 32 14.3 32 32v64c0 17.7-14.3 32-32 32H288c-17.7 0-32-14.3-32-32V224zM368 432h32V400H368v32zm-48-48c0-17.7 14.3-32 32-32h64c17.7 0 32 14.3 32 32v64c0 17.7-14.3 32-32 32H352c-17.7 0-32-14.3-32-32V384zM208 400v32h32V400H208zm-16-48h64c17.7 0 32 14.3 32 32v64c0 17.7-14.3 32-32 32H192c-17.7 0-32-14.3-32-32V384c0-17.7 14.3-32 32-32zM48 432H80V400H48v32zM0 384c0-17.7 14.3-32 32-32H96c17.7 0 32 14.3 32 32v64c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32V384z"/>',
|
||||
},
|
||||
{
|
||||
box: 25,
|
||||
name: 'linux',
|
||||
svg: '<path d="M12.504 0c-.155 0-.315.008-.48.021-4.226.333-3.105 4.807-3.17 6.298-.076 1.092-.3 1.953-1.05 3.02-.885 1.051-2.127 2.75-2.716 4.521-.278.832-.41 1.684-.287 2.489a.424.424 0 00-.11.135c-.26.268-.45.6-.663.839-.199.199-.485.267-.797.4-.313.136-.658.269-.864.68-.09.189-.136.394-.132.602 0 .199.027.4.055.536.058.399.116.728.04.97-.249.68-.28 1.145-.106 1.484.174.334.535.47.94.601.81.2 1.91.135 2.774.6.926.466 1.866.67 2.616.47.526-.116.97-.464 1.208-.946.587-.003 1.23-.269 2.26-.334.699-.058 1.574.267 2.577.2.025.134.063.198.114.333l.003.003c.391.778 1.113 1.132 1.884 1.071.771-.06 1.592-.536 2.257-1.306.631-.765 1.683-1.084 2.378-1.503.348-.199.629-.469.649-.853.023-.4-.2-.811-.714-1.376v-.097l-.003-.003c-.17-.2-.25-.535-.338-.926-.085-.401-.182-.786-.492-1.046h-.003c-.059-.054-.123-.067-.188-.135a.357.357 0 00-.19-.064c.431-1.278.264-2.55-.173-3.694-.533-1.41-1.465-2.638-2.175-3.483-.796-1.005-1.576-1.957-1.56-3.368.026-2.152.236-6.133-3.544-6.139zm.529 3.405h.013c.213 0 .396.062.584.198.19.135.33.332.438.533.105.259.158.459.166.724 0-.02.006-.04.006-.06v.105a.086.086 0 01-.004-.021l-.004-.024a1.807 1.807 0 01-.15.706.953.953 0 01-.213.335.71.71 0 00-.088-.042c-.104-.045-.198-.064-.284-.133a1.312 1.312 0 00-.22-.066c.05-.06.146-.133.183-.198.053-.128.082-.264.088-.402v-.02a1.21 1.21 0 00-.061-.4c-.045-.134-.101-.2-.183-.333-.084-.066-.167-.132-.267-.132h-.016c-.093 0-.176.03-.262.132a.8.8 0 00-.205.334 1.18 1.18 0 00-.09.4v.019c.002.089.008.179.02.267-.193-.067-.438-.135-.607-.202a1.635 1.635 0 01-.018-.2v-.02a1.772 1.772 0 01.15-.768c.082-.22.232-.406.43-.533a.985.985 0 01.594-.2zm-2.962.059h.036c.142 0 .27.048.399.135.146.129.264.288.344.465.09.199.14.4.153.667v.004c.007.134.006.2-.002.266v.08c-.03.007-.056.018-.083.024-.152.055-.274.135-.393.2.012-.09.013-.18.003-.267v-.015c-.012-.133-.04-.2-.082-.333a.613.613 0 00-.166-.267.248.248 0 00-.183-.064h-.021c-.071.006-.13.04-.186.132a.552.552 0 00-.12.27.944.944 0 00-.023.33v.015c.012.135.037.2.08.334.046.134.098.2.166.268.01.009.02.018.034.024-.07.057-.117.07-.176.136a.304.304 0 01-.131.068 2.62 2.62 0 01-.275-.402 1.772 1.772 0 01-.155-.667 1.759 1.759 0 01.08-.668 1.43 1.43 0 01.283-.535c.128-.133.26-.2.418-.2zm1.37 1.706c.332 0 .733.065 1.216.399.293.2.523.269 1.052.468h.003c.255.136.405.266.478.399v-.131a.571.571 0 01.016.47c-.123.31-.516.643-1.063.842v.002c-.268.135-.501.333-.775.465-.276.135-.588.292-1.012.267a1.139 1.139 0 01-.448-.067 3.566 3.566 0 01-.322-.198c-.195-.135-.363-.332-.612-.465v-.005h-.005c-.4-.246-.616-.512-.686-.71-.07-.268-.005-.47.193-.6.224-.135.38-.271.483-.336.104-.074.143-.102.176-.131h.002v-.003c.169-.202.436-.47.839-.601.139-.036.294-.065.466-.065zm2.8 2.142c.358 1.417 1.196 3.475 1.735 4.473.286.534.855 1.659 1.102 3.024.156-.005.33.018.513.064.646-1.671-.546-3.467-1.089-3.966-.22-.2-.232-.335-.123-.335.59.534 1.365 1.572 1.646 2.757.13.535.16 1.104.021 1.67.067.028.135.06.205.067 1.032.534 1.413.938 1.23 1.537v-.043c-.06-.003-.12 0-.18 0h-.016c.151-.467-.182-.825-1.065-1.224-.915-.4-1.646-.336-1.77.465-.008.043-.013.066-.018.135-.068.023-.139.053-.209.064-.43.268-.662.669-.793 1.187-.13.533-.17 1.156-.205 1.869v.003c-.02.334-.17.838-.319 1.35-1.5 1.072-3.58 1.538-5.348.334a2.645 2.645 0 00-.402-.533 1.45 1.45 0 00-.275-.333c.182 0 .338-.03.465-.067a.615.615 0 00.314-.334c.108-.267 0-.697-.345-1.163-.345-.467-.931-.995-1.788-1.521-.63-.4-.986-.87-1.15-1.396-.165-.534-.143-1.085-.015-1.645.245-1.07.873-2.11 1.274-2.763.107-.065.037.135-.408.974-.396.751-1.14 2.497-.122 3.854a8.123 8.123 0 01.647-2.876c.564-1.278 1.743-3.504 1.836-5.268.048.036.217.135.289.202.218.133.38.333.59.465.21.201.477.335.876.335.039.003.075.006.11.006.412 0 .73-.134.997-.268.29-.134.52-.334.74-.4h.005c.467-.135.835-.402 1.044-.7zm2.185 8.958c.037.6.343 1.245.882 1.377.588.134 1.434-.333 1.791-.765l.211-.01c.315-.007.577.01.847.268l.003.003c.208.199.305.53.391.876.085.4.154.78.409 1.066.486.527.645.906.636 1.14l.003-.007v.018l-.003-.012c-.015.262-.185.396-.498.595-.63.401-1.746.712-2.457 1.57-.618.737-1.37 1.14-2.036 1.191-.664.053-1.237-.2-1.574-.898l-.005-.003c-.21-.4-.12-1.025.056-1.69.176-.668.428-1.344.463-1.897.037-.714.076-1.335.195-1.814.12-.465.308-.797.641-.984l.045-.022zm-10.814.049h.01c.053 0 .105.005.157.014.376.055.706.333 1.023.752l.91 1.664.003.003c.243.533.754 1.064 1.189 1.637.434.598.77 1.131.729 1.57v.006c-.057.744-.48 1.148-1.125 1.294-.645.135-1.52.002-2.395-.464-.968-.536-2.118-.469-2.857-.602-.369-.066-.61-.2-.723-.4-.11-.2-.113-.602.123-1.23v-.004l.002-.003c.117-.334.03-.752-.027-1.118-.055-.401-.083-.71.043-.94.16-.334.396-.4.69-.533.294-.135.64-.202.915-.47h.002v-.002c.256-.268.445-.601.668-.838.19-.201.38-.336.663-.336zm7.159-9.074c-.435.201-.945.535-1.488.535-.542 0-.97-.267-1.28-.466-.154-.134-.28-.268-.373-.335-.164-.134-.144-.333-.074-.333.109.016.129.134.199.2.096.066.215.2.36.333.292.2.68.467 1.167.467.485 0 1.053-.267 1.398-.466.195-.135.445-.334.648-.467.156-.136.149-.267.279-.267.128.016.034.134-.Line truncated
|
||||
},
|
||||
{
|
||||
box: 25,
|
||||
name: 'windows',
|
||||
svg: '<path d="M0,0H11.377V11.372H0ZM12.623,0H24V11.372H12.623ZM0,12.623H11.377V24H0Zm12.623,0H24V24H12.623"/>',
|
||||
},
|
||||
{
|
||||
box: 500,
|
||||
name: 'unknown',
|
||||
svg: '<path d="M64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zm73.8 133.3c7.9-22.3 29.1-37.3 52.8-37.3h58.3c34.9 0 63.1 28.3 63.1 63.1c0 22.6-12.1 43.5-31.7 54.8L248 264.4c-.2 13-10.9 23.6-24 23.6c-13.3 0-24-10.7-24-24V250.5c0-8.6 4.6-16.5 12.1-20.8l44.3-25.4c4.7-2.7 7.6-7.7 7.6-13.1c0-8.4-6.8-15.1-15.1-15.1H190.6c-3.4 0-6.4 2.1-7.5 5.3l-.4 1.2c-4.4 12.5-18.2 19-30.6 14.6s-19-18.2-14.6-30.6l.4-1.2zM192 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"/>',
|
||||
},
|
||||
];
|
||||
let displayIcon = icons.find((e) => e.name === name);
|
||||
</script>
|
||||
|
||||
<svg
|
||||
{focusable}
|
||||
{width}
|
||||
{height}
|
||||
class={$$props.class + `${hover ? ' hover' : ''}`}
|
||||
style={`--iconColor: ${color}; --iconHoverColor: ${hoverColor};`}
|
||||
viewBox="0 0 {displayIcon?.box} {displayIcon?.box}"
|
||||
>
|
||||
{@html displayIcon?.svg}
|
||||
</svg>
|
||||
|
||||
<style lang="scss">
|
||||
svg {
|
||||
fill: var(--iconColor);
|
||||
transition: all 0.25s ease-in-out;
|
||||
&:hover,
|
||||
&.hover {
|
||||
animation: colorFade 0.25s ease-in-out;
|
||||
fill: var(--iconHoverColor);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes colorFade {
|
||||
0% {
|
||||
fill: var(--iconColor);
|
||||
}
|
||||
100% {
|
||||
fill: var(--iconHoverColor);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,38 @@
|
||||
<script lang="ts">
|
||||
export let searchTerm: string;
|
||||
</script>
|
||||
|
||||
<div class="title-row">
|
||||
<h2>Template List</h2>
|
||||
<div class="filters">
|
||||
<input type="text" placeholder="Search..." bind:value={searchTerm} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.title-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 1rem auto;
|
||||
padding: 0 1rem;
|
||||
max-width: var(--max-width);
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
margin: 0;
|
||||
}
|
||||
.filters {
|
||||
input {
|
||||
background: var(--card);
|
||||
border: 1px solid transparent;
|
||||
color: var(--foreground);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 6px;
|
||||
transition:all 0.3s ease-in-out;
|
||||
&:focus, &:hover {
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,36 @@
|
||||
<div class="nout">
|
||||
<h3>No Results 😢</h3>
|
||||
<p>
|
||||
<i>There weren't any templates found that matched the currently applied filters.</i><br><br>
|
||||
Check the raw <a href="https://github.com/Lissy93/portainer-templates/blob/main/templates.json"><code>templates.json</code></a> file
|
||||
to see all results.
|
||||
If you still can't find what you're looking for, why not
|
||||
<a href="https://github.com/Lissy93/portainer-templates#editing">submit a template</a>?
|
||||
Feel free to raise a ticket if you need support.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.nout {
|
||||
background: var(--card);
|
||||
border-radius: 6px;
|
||||
min-height: 8rem;
|
||||
margin: 1rem auto 5rem auto;
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
max-width: 650px;
|
||||
h3 {
|
||||
margin: 0;
|
||||
font-size: 3rem;
|
||||
}
|
||||
p {
|
||||
font-size: 1.1rem;
|
||||
code, a {
|
||||
color: var(--accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,53 @@
|
||||
<script lang="ts">
|
||||
export let searchTerm: string;
|
||||
export let selectedCategories: string[];
|
||||
export let clearSearch: () => void;
|
||||
export let numResults: number;
|
||||
export let totalResults: number;
|
||||
</script>
|
||||
|
||||
<div class="search-summary">
|
||||
{#if searchTerm}
|
||||
<p>
|
||||
Showing {numResults} of {totalResults}
|
||||
results, matching "<i>{searchTerm}</i>"
|
||||
{selectedCategories.length ? `in categories: ${selectedCategories.join(', ')}` : ''}
|
||||
</p>
|
||||
{:else if selectedCategories.length}
|
||||
<p>
|
||||
Showing {numResults} of {totalResults}
|
||||
results, matching categories: {selectedCategories.join(', ')}
|
||||
</p>
|
||||
{/if}
|
||||
{#if searchTerm || selectedCategories.length}
|
||||
<button on:click={clearSearch}>⨯ Clear Filters</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.search-summary {
|
||||
margin: 0 1rem;
|
||||
|
||||
font-size: 0.9rem;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
p {
|
||||
opacity: 0.75;
|
||||
}
|
||||
button {
|
||||
background: var(--gradient);
|
||||
outline: none;
|
||||
border: none;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 6px;
|
||||
color: var(--foreground);
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease-in-out;
|
||||
&:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,69 @@
|
||||
<script lang="ts">
|
||||
export let templates: any;
|
||||
</script>
|
||||
|
||||
<section class="templates">
|
||||
{#each templates as template}
|
||||
<div class="template-card">
|
||||
<h3>{template.title}</h3>
|
||||
<div class="template-summary">
|
||||
<div class="left">
|
||||
<img src={template.logo} alt={template.title} />
|
||||
</div>
|
||||
<div class="txt">
|
||||
<p class="description" title={template.description}>{template.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</section>
|
||||
|
||||
<style lang="scss">
|
||||
section.templates {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1rem;
|
||||
margin: 1rem auto;
|
||||
padding: 0 1rem;
|
||||
max-width: var(--max-width);
|
||||
.template-card {
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
background: var(--card);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
transition:all 0.3s ease-in-out;
|
||||
max-width: 28rem;
|
||||
&:hover {
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
.template-summary {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
}
|
||||
.left {
|
||||
.info-icons { opacity: 0.3; }
|
||||
}
|
||||
p, h3 {
|
||||
margin: 0;
|
||||
}
|
||||
img {
|
||||
width: 64px;
|
||||
max-height: 64px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.description {
|
||||
font-style: italic;
|
||||
font-weight: 200;
|
||||
overflow: hidden;
|
||||
word-break: break-word;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 5;
|
||||
line-clamp: 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,101 @@
|
||||
<script lang="ts">
|
||||
import Hero from '$lib/Hero.svelte';
|
||||
import ListFilter from '$lib/ListFilter.svelte';
|
||||
import Categories from '$lib/Categories.svelte';
|
||||
import SearchSummary from '$lib/SearchSummary.svelte';
|
||||
import Templates from '$lib/TemplateList.svelte';
|
||||
import NoResults from '$lib/NoResults.svelte';
|
||||
import Footer from '$lib/Footer.svelte';
|
||||
|
||||
export let data;
|
||||
|
||||
let searchTerm = '';
|
||||
|
||||
let selectedCategories: string[] = [];
|
||||
|
||||
$: filteredTemplates = data.templates.filter((template: any) => {
|
||||
const compareStr = (str1: string, str2: string) =>
|
||||
(str1 || '').toLowerCase().includes(str2.toLowerCase());
|
||||
|
||||
if (selectedCategories.length) {
|
||||
const templateCategories = template.categories || [];
|
||||
const hasSelectedCategory = selectedCategories.some((cat) =>
|
||||
templateCategories.includes(cat)
|
||||
);
|
||||
if (!hasSelectedCategory) return false;
|
||||
}
|
||||
return (
|
||||
compareStr(template.title, searchTerm) ||
|
||||
compareStr(template.description, searchTerm) ||
|
||||
compareStr((template.categories || []).join(''), searchTerm)
|
||||
);
|
||||
});
|
||||
|
||||
const toggleCategory = (category: string) => {
|
||||
if (selectedCategories.includes(category)) {
|
||||
selectedCategories = selectedCategories.filter((cat) => cat !== category);
|
||||
} else {
|
||||
selectedCategories = [...selectedCategories, category];
|
||||
}
|
||||
};
|
||||
|
||||
const clearSearch = () => {
|
||||
searchTerm = '';
|
||||
selectedCategories = [];
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Main title, and CTA buttons -->
|
||||
<Hero />
|
||||
|
||||
<!-- Search bar, and Templates sub-title -->
|
||||
<ListFilter bind:searchTerm={searchTerm} />
|
||||
|
||||
<!-- List of categories to filter by -->
|
||||
<Categories
|
||||
categories={data.categories}
|
||||
selectedCategories={selectedCategories}
|
||||
toggleCategory={toggleCategory}
|
||||
/>
|
||||
|
||||
<!-- Text showing num results, and users search term + filters -->
|
||||
<SearchSummary
|
||||
searchTerm={searchTerm}
|
||||
selectedCategories={selectedCategories}
|
||||
clearSearch={clearSearch}
|
||||
numResults={filteredTemplates.length}
|
||||
totalResults={data.templates.length}
|
||||
/>
|
||||
|
||||
<!-- List of available templates (filtered, if needed) -->
|
||||
<Templates templates={filteredTemplates} />
|
||||
|
||||
<!-- If there are no templates matching search term, show lil message -->
|
||||
{#if !filteredTemplates.length}
|
||||
<NoResults />
|
||||
{/if}
|
||||
|
||||
<!-- Footer showing license and source code links -->
|
||||
<Footer />
|
||||
|
||||
<style lang="scss">
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@200;400;800&display=swap');
|
||||
:global(body) {
|
||||
--background: #101828;
|
||||
--foreground: #ffffff;
|
||||
--accent: #0ba5ec;
|
||||
--card: #1d2939;
|
||||
--shadow: 1px 1px 3px 3px #0B9AEC8F;
|
||||
--gradient: linear-gradient(to right,#0B9AEC 0%,#6EDFDE 100%);
|
||||
--max-width: 1800px;
|
||||
margin: 0;
|
||||
font-family: 'Kanit', sans-serif;
|
||||
color: var(--foreground);
|
||||
background: var(--background);
|
||||
}
|
||||
:global(::selection) {
|
||||
background: var(--card);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
const makeCategories = (templates) => {
|
||||
// Get categories from templates
|
||||
const categories = templates.reduce((acc, { categories: templateCategories }) => {
|
||||
(templateCategories || []).forEach((category) => {
|
||||
acc[category] = (acc[category] || 0) + 1;
|
||||
});
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
// Sort categories by count, and remove categories with only 1 template
|
||||
const sortedCategories = Object.fromEntries(
|
||||
Object.entries(categories)
|
||||
.filter(([, value]) => value > 3)
|
||||
.sort(([, a], [, b]) => b - a)
|
||||
);
|
||||
|
||||
return sortedCategories;
|
||||
};
|
||||
|
||||
|
||||
export const load = async () => {
|
||||
const url = 'https://raw.githubusercontent.com/Lissy93/portainer-templates/main/templates.json';
|
||||
const data = await fetch(url).then((res) => res.json());
|
||||
|
||||
return {
|
||||
templates: data.templates,
|
||||
categories: makeCategories(data.templates),
|
||||
}
|
||||
};
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,18 @@
|
||||
import adapter from '@sveltejs/adapter-auto';
|
||||
import { vitePreprocess } from '@sveltejs/kit/vite';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||
// for more information about preprocessors
|
||||
preprocess: vitePreprocess(),
|
||||
|
||||
kit: {
|
||||
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
||||
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
|
||||
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
||||
adapter: adapter()
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true
|
||||
}
|
||||
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||
//
|
||||
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()]
|
||||
});
|
||||
Reference in new issue
Block a user