initial production release 🎉

This commit is contained in:
Andras
2021-03-24 22:11:14 +01:00
commit dbe82b3e7c
101 changed files with 12479 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
<script>
import { application} from "@store";
</script>
<div class="grid grid-cols-1 space-y-2 max-w-2xl md:mx-auto mx-6 text-center">
<label for="buildCommand">Build Command</label>
<input
id="buildCommand"
bind:value="{$application.build.command.build}"
placeholder="eg: yarn build"
/>
<label for="installCommand">Install Command</label>
<input
id="installCommand"
bind:value="{$application.build.command.installation}"
placeholder="eg: yarn install"
/>
<label for="baseDir">Base Directory</label>
<input id="baseDir" bind:value="{$application.build.directory}" placeholder="/" />
</div>

View File

@@ -0,0 +1,106 @@
<script>
import { application } from "@store";
</script>
<div>
<div
class="grid grid-cols-1 text-sm space-y-2 max-w-2xl md:mx-auto mx-6 pb-6 auto-cols-max"
>
<label for="buildPack">Build Pack</label>
<select id="buildPack" bind:value="{$application.build.pack}">
<option selected class="font-medium">static</option>
<option class="font-medium">nodejs</option>
</select>
</div>
<div
class="grid grid-cols-2 space-y-2 max-w-2xl md:mx-auto mx-6 justify-center items-center"
>
<label for="Domain">Domain</label>
<input
class:placeholder-red-500="{$application.publish.domain == null || $application.publish.domain == ''}"
class:border-red-500="{$application.publish.domain == null || $application.publish.domain == ''}"
id="Domain"
bind:value="{$application.publish.domain}"
placeholder="eg: coollabs.io (without www)"
/>
<label for="Path">Path Prefix</label>
<input
id="Path"
bind:value="{$application.publish.path}"
placeholder="/"
/>
<label for="publishDir">Publish Directory</label>
<input
id="publishDir"
bind:value="{$application.publish.directory}"
placeholder="/"
/>
{#if $application.build.pack !== "static"}
<label for="Port">Port</label>
<input
id="Port"
bind:value="{$application.publish.port}"
placeholder="{$application.build.pack === 'static'
? '80'
: '3000'}"
/>
{/if}
<!-- {#if config.buildPack === "static"}
<div class="text-base font-bold text-white pt-2">
Preview Deploys
</div>
<button
type="button"
on:click="{() =>
(config.previewDeploy = !config.previewDeploy)}"
aria-pressed="false"
class="relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black"
class:bg-green-600="{config.previewDeploy}"
class:bg-coolgray-300="{!config.previewDeploy}"
>
<span class="sr-only">Use setting</span>
<span
class="pointer-events-none relative inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200"
class:translate-x-5="{config.previewDeploy}"
class:translate-x-0="{!config.previewDeploy}"
>
<span
class="ease-in duration-200 absolute inset-0 h-full w-full flex items-center justify-center transition-opacity"
class:opacity-0="{config.previewDeploy}"
class:opacity-100="{!config.previewDeploy}"
aria-hidden="true"
>
<svg
class="bg-white h-3 w-3 text-red-600"
fill="none"
viewBox="0 0 12 12"
>
<path
d="M4 8l2-2m0 0l2-2M6 6L4 4m2 2l2 2"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"></path>
</svg>
</span>
<span
class="ease-out duration-100 absolute inset-0 h-full w-full flex items-center justify-center transition-opacity"
aria-hidden="true"
class:opacity-100="{config.previewDeploy}"
class:opacity-0="{!config.previewDeploy}"
>
<svg
class="bg-white h-3 w-3 text-green-600"
fill="currentColor"
viewBox="0 0 12 12"
>
<path
d="M3.707 5.293a1 1 0 00-1.414 1.414l1.414-1.414zM5 8l-.707.707a1 1 0 001.414 0L5 8zm4.707-3.293a1 1 0 00-1.414-1.414l1.414 1.414zm-7.414 2l2 2 1.414-1.414-2-2-1.414 1.414zm3.414 2l4-4-1.414-1.414-4 4 1.414 1.414z"
></path>
</svg>
</span>
</span>
</button>
{/if} -->
</div>
</div>

View File

@@ -0,0 +1,72 @@
<script>
import { application } from "@store";
let secret = {
name: null,
value: null,
};
let foundSecret = null;
async function saveSecret() {
if (secret.name && secret.value) {
const found = $application.publish.secrets.find(
s => s.name === secret.name,
);
if (!found) {
$application.publish.secrets = [
...$application.publish.secrets,
{
name: secret.name,
value: secret.value,
},
];
secret = {
name: null,
value: null
}
} else {
foundSecret = found;
}
}
}
async function removeSecret(name) {
$application.publish.secrets = [...$application.publish.secrets.filter(s => s.name !== name)]
}
</script>
<div class="space-y-2 max-w-2xl md:mx-auto mx-6 text-center">
<div class="text-left text-base font-bold tracking-tight text-warmGray-400">New Secret</div>
<div class="grid md:grid-flow-col grid-flow-row gap-2">
<input id="secretName" bind:value="{secret.name}" placeholder="Name" />
<input id="secretValue" bind:value="{secret.value}" placeholder="Value" />
<button
class="button p-1 w-20 bg-green-600 hover:bg-green-500 text-white"
on:click="{saveSecret}">Save</button
>
</div>
{#if $application.publish.secrets.length > 0}
{#each $application.publish.secrets as s}
<div class="grid md:grid-flow-col grid-flow-row gap-2">
<input
id="{s.name}"
value="{s.name}"
disabled
class="bg-transparent border-transparent"
class:border-red-600="{foundSecret && foundSecret.name === s.name}"
/>
<input
id="{s.createdAt}"
value="ENCRYPTED"
disabled
class="bg-transparent border-transparent"
/>
<button
class="button w-20 bg-red-600 hover:bg-red-500 text-white"
on:click="{() => removeSecret(s.name)}">Delete</button
>
</div>
{/each}
{/if}
</div>

View File

@@ -0,0 +1,24 @@
<script>
export let loading, branches;
import { application } from "@store";
</script>
{#if loading}
<div class="grid grid-cols-1">
<label for="branch">Branch</label>
<select disabled>
<option selected>Loading branches</option>
</select>
</div>
{:else}
<div class="grid grid-cols-1">
<label for="branch">Branch</label>
<!-- svelte-ignore a11y-no-onchange -->
<select id="branch" bind:value="{$application.repository.branch}">
<option disabled selected>Select a branch</option>
{#each branches as branch}
<option value="{branch.name}" class="font-medium">{branch.name}</option>
{/each}
</select>
</div>
{/if}

View File

@@ -0,0 +1,133 @@
<script>
import { redirect, isActive } from "@roxi/routify";
import { fade } from "svelte/transition";
import { session, application, fetch, initialApplication } from "@store";
import Login from "./Login.svelte";
import Loading from "../../Loading.svelte";
import Repositories from "./Repositories.svelte";
import Branches from "./Branches.svelte";
import Tabs from "./Tabs.svelte";
let loading = {
branches: false,
};
let branches = [];
let repositories = [];
async function loadBranches() {
loading.branches = true;
const selectedRepository = repositories.find(
r => r.id === $application.repository.id,
);
if (selectedRepository) {
$application.repository.organization = selectedRepository.owner.login;
$application.repository.name = selectedRepository.name;
}
branches = await $fetch(
`https://api.github.com/repos/${$application.repository.organization}/${$application.repository.name}/branches`,
);
loading.branches = false;
}
async function loadGithub() {
try {
const { installations } = await $fetch(
"https://api.github.com/user/installations",
);
if (installations.length === 0) {
return false;
}
$application.github.installation.id = installations[0].id;
$application.github.app.id = installations[0].app_id;
const data = await $fetch(
`https://api.github.com/user/installations/${$application.github.installation.id}/repositories?per_page=10000`,
);
repositories = data.repositories;
const foundRepositoryOnGithub = data.repositories.find(
r =>
r.full_name ===
`${$application.repository.organization}/${$application.repository.name}`,
);
if (foundRepositoryOnGithub) {
$application.repository.id = foundRepositoryOnGithub.id;
await loadBranches();
}
} catch (error) {
return false;
}
}
function modifyGithubAppConfig() {
const left = screen.width / 2 - 1020 / 2;
const top = screen.height / 2 - 618 / 2;
const newWindow = open(
`https://github.com/apps/${
import.meta.env.VITE_GITHUB_APP_NAME
}/installations/new`,
"Install App",
"resizable=1, scrollbars=1, fullscreen=0, height=1000, width=1020,top=" +
top +
", left=" +
left +
", toolbar=0, menubar=0, status=0",
);
const timer = setInterval(async () => {
if (newWindow.closed) {
clearInterval(timer);
if (!$isActive("/application/new")) {
try {
const config = await $fetch(`/api/v1/config`, {
body: {
name: $application.repository.name,
organization: $application.repository.organization,
branch: $application.repository.branch,
},
});
$application = { ...config };
} catch (error) {
$redirect("/dashboard/applications");
}
} else {
$application = JSON.parse(JSON.stringify(initialApplication));
}
branches = [];
repositories = [];
await loadGithub();
}
}, 100);
}
</script>
<div in:fade="{{ duration: 100 }}">
{#if !$session.githubAppToken}
<Login />
{:else}
{#await loadGithub()}
<Loading />
{:then}
<div
class="text-center space-y-2 max-w-4xl mx-auto px-6"
in:fade="{{ duration: 100 }}"
>
<Repositories
bind:repositories
on:loadBranches="{loadBranches}"
on:modifyGithubAppConfig="{modifyGithubAppConfig}"
/>
{#if $application.repository.organization !== "new"}
<Branches loading="{loading.branches}" branches="{branches}" />
{/if}
{#if $application.repository.branch}
<Tabs />
{/if}
</div>
{/await}
{/if}
</div>

View File

@@ -0,0 +1,50 @@
<script>
import { session } from "@store";
function login() {
const left = screen.width / 2 - 1020 / 2;
const top = screen.height / 2 - 618 / 2;
const newWindow = open(
`https://github.com/login/oauth/authorize?client_id=${
import.meta.env.VITE_GITHUB_APP_CLIENTID
}`,
"Authenticate",
"resizable=1, scrollbars=1, fullscreen=0, height=618, width=1020,top=" +
top +
", left=" +
left +
", toolbar=0, menubar=0, status=0",
);
const timer = setInterval(() => {
if (newWindow.closed) {
clearInterval(timer);
const ghToken = new URL(newWindow.document.URL).searchParams.get(
"ghToken",
);
if (ghToken) {
$session.githubAppToken = ghToken;
}
}
}, 100);
}
</script>
<div class="text-center text-white">
<div class="text-2xl font-bold text-center pb-4">
Choose your Git provider
</div>
<button on:click="{login}" class="hover:scale-110 transform duration-100 transition">
<svg
class="w-16"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
><path
d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"
></path></svg
>
</button>
</div>

View File

@@ -0,0 +1,45 @@
<script>
import { createEventDispatcher } from "svelte";
import { isActive } from "@roxi/routify";
import { application } from "@store";
export let repositories;
const dispatch = createEventDispatcher();
const loadBranches = () => dispatch("loadBranches");
const modifyGithubAppConfig = () => dispatch("modifyGithubAppConfig");
</script>
<div class="grid grid-cols-1">
{#if repositories.length !== 0}
<label for="repository">Organization / Repository</label>
<div class="grid grid-cols-3">
<!-- svelte-ignore a11y-no-onchange -->
<select
id="repository"
class:cursor-not-allowed="{!$isActive('/application/new')}"
class="col-span-2"
bind:value="{$application.repository.id}"
on:change="{loadBranches}"
disabled="{!$isActive('/application/new')}"
>
<option selected disabled>Select a repository</option>
{#each repositories as repo}
<option value="{repo.id}" class="font-medium">
{repo.owner.login}
/
{repo.name}
</option>
{/each}
</select>
<button
class="button col-span-1 ml-2 bg-warmGray-800 hover:bg-warmGray-700 text-white"
on:click="{modifyGithubAppConfig}">Configure on Github</button
>
</div>
{:else}
<button
class="button col-span-1 ml-2 bg-warmGray-800 hover:bg-warmGray-700 text-white"
on:click="{modifyGithubAppConfig}">Add repositories on Github</button
>
{/if}
</div>

View File

@@ -0,0 +1,97 @@
<script>
import { redirect, isActive } from "@roxi/routify";
import { application, fetch, deployments } from "@store";
import General from "./ActiveTab/General.svelte";
import BuildStep from "./ActiveTab/BuildStep.svelte";
import Secrets from "./ActiveTab/Secrets.svelte";
import { onMount } from "svelte";
onMount(async () => {
if (!$isActive("/application/new")) {
const config = await $fetch(`/api/v1/config`, {
body: {
name: $application.repository.name,
organization: $application.repository.organization,
branch: $application.repository.branch,
},
});
$application = { ...config };
$redirect(`/application/:organization/:name/:branch/configuration`, {
name: $application.repository.name,
organization: $application.repository.organization,
branch: $application.repository.branch,
});
} else {
$deployments.applications.deployed.filter(d => {
const conf = d?.Spec?.Labels.application;
if (
conf.repository.organization ===
$application.repository.organization &&
conf.repository.name === $application.repository.name &&
conf.repository.branch === $application.repository.branch
) {
$redirect(`/application/:organization/:name/:branch/configuration`, {
name: $application.repository.name,
organization: $application.repository.organization,
branch: $application.repository.branch,
});
}
});
}
});
let activeTab = {
general: true,
buildStep: false,
secrets: false,
};
function activateTab(tab) {
if (activeTab.hasOwnProperty(tab)) {
activeTab = {
general: false,
buildStep: false,
secrets: false,
};
activeTab[tab] = true;
}
}
</script>
<div class="block text-center py-4">
<nav
class="flex space-x-4 justify-center font-bold text-md text-white"
aria-label="Tabs"
>
<div
on:click="{() => activateTab('general')}"
class:text-green-500="{activeTab.general}"
class="px-3 py-2 cursor-pointer hover:text-green-500"
>
General
</div>
<div
on:click="{() => activateTab('buildStep')}"
class:text-green-500="{activeTab.buildStep}"
class="px-3 py-2 cursor-pointer hover:text-green-500"
>
Build Step
</div>
<div
on:click="{() => activateTab('secrets')}"
class:text-green-500="{activeTab.secrets}"
class="px-3 py-2 cursor-pointer hover:text-green-500"
>
Secrets
</div>
</nav>
</div>
<div class="max-w-4xl mx-auto">
<div class="h-full">
{#if activeTab.general}
<General />
{:else if activeTab.buildStep}
<BuildStep />
{:else if activeTab.secrets}
<Secrets />
{/if}
</div>
</div>

View File

@@ -0,0 +1,90 @@
<script>
import { fetch, dbInprogress } from "@store";
import { isActive, redirect } from "@roxi/routify/runtime";
import { fade } from "svelte/transition";
import { toast } from "@zerodevx/svelte-toast";
let type;
let defaultDatabaseName;
async function deploy() {
try {
await $fetch(`/api/v1/databases/deploy`, {
body: {
type,
defaultDatabaseName,
},
});
$dbInprogress = true
toast.push("Database deployment queued.");
$redirect(`/dashboard/databases`);
} catch (error) {
console.log(error);
}
}
</script>
<div
class="text-center space-y-2 max-w-4xl mx-auto px-6"
in:fade="{{ duration: 100 }}"
>
{#if $isActive("/database/new")}
<div class="flex justify-center space-x-4 font-bold pb-6">
<button
class="button bg-gray-500 p-2 text-white hover:bg-green-600 cursor-pointer w-32"
on:click="{() => (type = 'mongodb')}"
class:bg-green-600="{type === 'mongodb'}"
>
MongoDB
</button>
<button
class="button bg-gray-500 p-2 text-white hover:bg-blue-600 cursor-pointer w-32"
on:click="{() => (type = 'postgresql')}"
class:bg-blue-600="{type === 'postgresql'}"
>
PostgreSQL
</button>
<button
class="button bg-gray-500 p-2 text-white hover:bg-orange-600 cursor-pointer w-32"
on:click="{() => (type = 'mysql')}"
class:bg-orange-600="{type === 'mysql'}"
>
MySQL
</button>
<button
class="button bg-gray-500 p-2 text-white hover:bg-red-600 cursor-pointer w-32"
on:click="{() => (type = 'couchdb')}"
class:bg-red-600="{type === 'couchdb'}"
>
Couchdb
</button>
</div>
{#if type}
<div>
<div
class="grid grid-rows-1 justify-center items-center text-center pb-5"
>
<label for="defaultDB">Default database</label>
<input
id="defaultDB"
class="w-64"
placeholder="random"
bind:value="{defaultDatabaseName}"
/>
</div>
<button
class:bg-green-600="{type === 'mongodb'}"
class:hover:bg-green-500="{type === 'mongodb'}"
class:bg-blue-600="{type === 'postgresql'}"
class:hover:bg-blue-500="{type === 'postgresql'}"
class:bg-orange-600="{type === 'mysql'}"
class:hover:bg-orange-500="{type === 'mysql'}"
class:bg-red-600="{type === 'couchdb'}"
class:hover:bg-red-500="{type === 'couchdb'}"
class="button p-2 w-32 text-white"
on:click="{deploy}">Deploy</button
>
</div>
{/if}
{/if}
</div>

View File

@@ -0,0 +1,16 @@
<script>
export let customClass;
</script>
<svg
class={customClass}
id="CouchDB"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 128 128"
><g id="original"
><path
class=""
d="M101.4,77.2c0,5-2.7,7.5-7.6,7.7H33.9c-4.9,0-7.6-2.5-7.6-7.7,0-5,2.7-7.5,7.6-7.7H94.1C99,69.7,101.4,72.2,101.4,77.2ZM94.1,88.7H33.9c-4.9,0-7.6,2.4-7.6,7.7,0,5,2.7,7.4,7.6,7.7H94.1c4.9,0,7.6-2.5,7.6-7.7C101.4,91.1,99,88.7,94.1,88.7Zm18.6-42.1h0c-4.9,0-7.6,2.5-7.6,7.4V96.1c0,5,2.7,7.5,7.6,7.7h0c7.4-.2,11.3-7.7,11.3-22.9V62C124,51.8,120.1,46.8,112.7,46.6Zm-97.4,0h0C7.9,46.8,4,51.8,4,62V80.9c0,15.2,3.9,22.7,11.3,22.9h0c4.9,0,7.6-2.4,7.6-7.7V54.3C22.7,49.3,20.2,46.8,15.3,46.6Zm97.4-3.8c0-12.7-6.6-18.7-18.6-18.9H33.9c-12.2.2-18.6,6.5-18.6,18.9h0c7.4,0,11.3,4,11.3,11.5s3.9,11.4,11.3,11.4H90.4c7.3,0,11.3-3.9,11.3-11.4-.3-7.7,3.9-11.2,11-11.5Z"
></path></g
></svg
>

View File

@@ -0,0 +1,32 @@
<script>
export let customClass;
</script>
<svg
class={customClass}
xmlns="http://www.w3.org/2000/svg"
id="Layer_1"
data-name="Layer 1"
viewBox="0 0 216.56 448.5"
><defs
><style>
.cls-1 {
fill: #10aa50;
}
.cls-2 {
fill: #b8c4c2;
}
.cls-3 {
fill: #12924f;
}
</style></defs
><title>MongoDB_Leaf_FullColor_RGB</title><path
class="cls-1"
d="M202.8,179.68c-23-101.47-71-128.49-83.18-147.59C113,21.7,106.25,5.91,106.25,5.91c-.66,9-1.83,14.7-9.51,21.54C81.36,41.16,16,94.42,10.51,209.72c-5.12,107.5,79,173.8,90.18,180.65,8.54,4.2,19,.08,24-3.77,40.54-27.84,96-102.07,78.06-206.92"
></path><path
class="cls-2"
d="M109.73,333.11c-2.11,26.62-3.63,42.11-9,57.29,0,0,3.54,25.33,6,52.17l8.77,0a488.62,488.62,0,0,1,9.57-56.2C113.71,380.8,110.16,356.46,109.73,333.11Z"
></path><path
class="cls-3"
d="M125.06,386.39h0c-11.48-5.3-14.8-30.13-15.31-53.28A1090.8,1090.8,0,0,0,112.2,218.4c-.6-20.07.3-185.92-4.94-210.2,2.12,4.75,7.24,15.91,12.36,23.88,12.23,19.11,60.19,46.13,83.17,147.61C220.7,284.27,165.57,358.37,125.06,386.39Z"
></path>
</svg>

View File

@@ -0,0 +1,16 @@
<script>
export let customClass;
</script>
<svg
class={customClass}
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
viewBox="0 0 25.6 25.6"
><path
d="M179.076 94.886c-3.568-.1-6.336.268-8.656 1.25-.668.27-1.74.27-1.828 1.116.357.355.4.936.713 1.428.535.893 1.473 2.096 2.32 2.72l2.855 2.053c1.74 1.07 3.703 1.695 5.398 2.766.982.625 1.963 1.428 2.945 2.098.5.357.803.938 1.428 1.16v-.135c-.312-.4-.402-.98-.713-1.428l-1.34-1.293c-1.293-1.74-2.9-3.258-4.64-4.506-1.428-.982-4.55-2.32-5.13-3.97l-.088-.1c.98-.1 2.14-.447 3.078-.715 1.518-.4 2.9-.312 4.46-.713l2.143-.625v-.4c-.803-.803-1.383-1.874-2.23-2.632-2.275-1.963-4.775-3.882-7.363-5.488-1.383-.892-3.168-1.473-4.64-2.23-.537-.268-1.428-.402-1.74-.848-.805-.98-1.25-2.275-1.83-3.436l-3.658-7.763c-.803-1.74-1.295-3.48-2.275-5.086-4.596-7.585-9.594-12.18-17.268-16.687-1.65-.937-3.613-1.34-5.7-1.83l-3.346-.18c-.715-.312-1.428-1.16-2.053-1.562-2.543-1.606-9.102-5.086-10.977-.5-1.205 2.9 1.785 5.755 2.8 7.228.76 1.026 1.74 2.186 2.277 3.346.3.758.4 1.562.713 2.365.713 1.963 1.383 4.15 2.32 5.98.5.937 1.025 1.92 1.65 2.767.357.5.982.714 1.115 1.517-.625.893-.668 2.23-1.025 3.347-1.607 5.042-.982 11.288 1.293 15 .715 1.115 2.4 3.57 4.686 2.632 2.008-.803 1.56-3.346 2.14-5.577.135-.535.045-.892.312-1.25v.1l1.83 3.703c1.383 2.186 3.793 4.462 5.8 5.98 1.07.803 1.918 2.187 3.256 2.677v-.135h-.088c-.268-.4-.67-.58-1.027-.892-.803-.803-1.695-1.785-2.32-2.677-1.873-2.498-3.523-5.265-4.996-8.12-.715-1.383-1.34-2.9-1.918-4.283-.27-.536-.27-1.34-.715-1.606-.67.98-1.65 1.83-2.143 3.034-.848 1.918-.936 4.283-1.248 6.737-.18.045-.1 0-.18.1-1.426-.356-1.918-1.83-2.453-3.078-1.338-3.168-1.562-8.254-.402-11.913.312-.937 1.652-3.882 1.117-4.774-.27-.848-1.16-1.338-1.652-2.008-.58-.848-1.203-1.918-1.605-2.855-1.07-2.5-1.605-5.265-2.766-7.764-.537-1.16-1.473-2.365-2.232-3.435-.848-1.205-1.783-2.053-2.453-3.48-.223-.5-.535-1.294-.178-1.83.088-.357.268-.5.623-.58.58-.5 2.232.134 2.812.4 1.65.67 3.033 1.294 4.416 2.23.625.446 1.295 1.294 2.098 1.518h.938c1.428.312 3.033.1 4.37.5 2.365.76 4.506 1.874 6.426 3.08 5.844 3.703 10.664 8.968 13.92 15.26.535 1.026.758 1.963 1.25 3.034.938 2.187 2.098 4.417 3.033 6.56.938 2.097 1.83 4.24 3.168 5.98.67.937 3.346 1.427 4.55 1.918.893.4 2.275.76 3.08 1.25 1.516.937 3.033 2.008 4.46 3.034.713.534 2.945 1.65 3.078 2.54zm-45.5-38.772a7.09 7.09 0 0 0-1.828.223v.1h.088c.357.714.982 1.205 1.428 1.83l1.027 2.142.088-.1c.625-.446.938-1.16.938-2.23-.268-.312-.312-.625-.535-.937-.268-.446-.848-.67-1.206-1.026z"
transform="matrix(.390229 0 0 .38781 -46.300037 -16.856717)"
fill-rule="evenodd"
fill="#00678c"></path></svg
>

View File

@@ -0,0 +1,60 @@
<script>
export let customClass;
</script>
<svg
class={customClass}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 432.071 445.383"
xml:space="preserve"
>
<g
id="orginal"
style="fill-rule:nonzero;clip-rule:nonzero;stroke:#000000;stroke-miterlimit:4;"
>
</g>
<g
id="Layer_x0020_3"
style="fill-rule:nonzero;clip-rule:nonzero;fill:none;stroke:#FFFFFF;stroke-width:12.4651;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;"
>
<path
style="fill:#000000;stroke:#000000;stroke-width:37.3953;stroke-linecap:butt;stroke-linejoin:miter;"
d="M323.205,324.227c2.833-23.601,1.984-27.062,19.563-23.239l4.463,0.392c13.517,0.615,31.199-2.174,41.587-7c22.362-10.376,35.622-27.7,13.572-23.148c-50.297,10.376-53.755-6.655-53.755-6.655c53.111-78.803,75.313-178.836,56.149-203.322 C352.514-5.534,262.036,26.049,260.522,26.869l-0.482,0.089c-9.938-2.062-21.06-3.294-33.554-3.496c-22.761-0.374-40.032,5.967-53.133,15.904c0,0-161.408-66.498-153.899,83.628c1.597,31.936,45.777,241.655,98.47,178.31 c19.259-23.163,37.871-42.748,37.871-42.748c9.242,6.14,20.307,9.272,31.912,8.147l0.897-0.765c-0.281,2.876-0.157,5.689,0.359,9.019c-13.572,15.167-9.584,17.83-36.723,23.416c-27.457,5.659-11.326,15.734-0.797,18.367c12.768,3.193,42.305,7.716,62.268-20.224 l-0.795,3.188c5.325,4.26,4.965,30.619,5.72,49.452c0.756,18.834,2.017,36.409,5.856,46.771c3.839,10.36,8.369,37.05,44.036,29.406c29.809-6.388,52.6-15.582,54.677-101.107"
></path>
<path
style="fill:#336791;stroke:none;"
d="M402.395,271.23c-50.302,10.376-53.76-6.655-53.76-6.655c53.111-78.808,75.313-178.843,56.153-203.326c-52.27-66.785-142.752-35.2-144.262-34.38l-0.486,0.087c-9.938-2.063-21.06-3.292-33.56-3.496c-22.761-0.373-40.026,5.967-53.127,15.902 c0,0-161.411-66.495-153.904,83.63c1.597,31.938,45.776,241.657,98.471,178.312c19.26-23.163,37.869-42.748,37.869-42.748c9.243,6.14,20.308,9.272,31.908,8.147l0.901-0.765c-0.28,2.876-0.152,5.689,0.361,9.019c-13.575,15.167-9.586,17.83-36.723,23.416 c-27.459,5.659-11.328,15.734-0.796,18.367c12.768,3.193,42.307,7.716,62.266-20.224l-0.796,3.188c5.319,4.26,9.054,27.711,8.428,48.969c-0.626,21.259-1.044,35.854,3.147,47.254c4.191,11.4,8.368,37.05,44.042,29.406c29.809-6.388,45.256-22.942,47.405-50.555 c1.525-19.631,4.976-16.729,5.194-34.28l2.768-8.309c3.192-26.611,0.507-35.196,18.872-31.203l4.463,0.392c13.517,0.615,31.208-2.174,41.591-7c22.358-10.376,35.618-27.7,13.573-23.148z"
></path>
<path
d="M215.866,286.484c-1.385,49.516,0.348,99.377,5.193,111.495c4.848,12.118,15.223,35.688,50.9,28.045c29.806-6.39,40.651-18.756,45.357-46.051c3.466-20.082,10.148-75.854,11.005-87.281"
></path>
<path
d="M173.104,38.256c0,0-161.521-66.016-154.012,84.109c1.597,31.938,45.779,241.664,98.473,178.316c19.256-23.166,36.671-41.335,36.671-41.335"
></path>
<path
d="M260.349,26.207c-5.591,1.753,89.848-34.889,144.087,34.417c19.159,24.484-3.043,124.519-56.153,203.329"
></path>
<path
style="stroke-linejoin:bevel;"
d="M348.282,263.953c0,0,3.461,17.036,53.764,6.653c22.04-4.552,8.776,12.774-13.577,23.155c-18.345,8.514-59.474,10.696-60.146-1.069c-1.729-30.355,21.647-21.133,19.96-28.739c-1.525-6.85-11.979-13.573-18.894-30.338 c-6.037-14.633-82.796-126.849,21.287-110.183c3.813-0.789-27.146-99.002-124.553-100.599c-97.385-1.597-94.19,119.762-94.19,119.762"
></path>
<path
d="M188.604,274.334c-13.577,15.166-9.584,17.829-36.723,23.417c-27.459,5.66-11.326,15.733-0.797,18.365c12.768,3.195,42.307,7.718,62.266-20.229c6.078-8.509-0.036-22.086-8.385-25.547c-4.034-1.671-9.428-3.765-16.361,3.994z"
></path>
<path
d="M187.715,274.069c-1.368-8.917,2.93-19.528,7.536-31.942c6.922-18.626,22.893-37.255,10.117-96.339c-9.523-44.029-73.396-9.163-73.436-3.193c-0.039,5.968,2.889,30.26-1.067,58.548c-5.162,36.913,23.488,68.132,56.479,64.938"
></path>
<path
style="fill:#FFFFFF;stroke-width:4.155;stroke-linecap:butt;stroke-linejoin:miter;"
d="M172.517,141.7c-0.288,2.039,3.733,7.48,8.976,8.207c5.234,0.73,9.714-3.522,9.998-5.559c0.284-2.039-3.732-4.285-8.977-5.015c-5.237-0.731-9.719,0.333-9.996,2.367z"
></path>
<path
style="fill:#FFFFFF;stroke-width:2.0775;stroke-linecap:butt;stroke-linejoin:miter;"
d="M331.941,137.543c0.284,2.039-3.732,7.48-8.976,8.207c-5.238,0.73-9.718-3.522-10.005-5.559c-0.277-2.039,3.74-4.285,8.979-5.015c5.239-0.73,9.718,0.333,10.002,2.368z"
></path>
<path
d="M350.676,123.432c0.863,15.994-3.445,26.888-3.988,43.914c-0.804,24.748,11.799,53.074-7.191,81.435"
></path>
<path style="stroke-width:3;" d="M0,60.232"></path>
</g>
</svg>

View File

@@ -0,0 +1,52 @@
<style lang="postcss">
.loader {
width: 8px;
height: 40px;
border-radius: 4px;
display: block;
margin: 20px auto;
position: relative;
background: currentColor;
color: #fff;
box-sizing: border-box;
animation: animloader 0.3s 0.3s linear infinite alternate;
}
.loader::after,
.loader::before {
content: "";
width: 8px;
height: 40px;
border-radius: 4px;
background: currentColor;
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 20px;
box-sizing: border-box;
animation: animloader 0.3s 0.45s linear infinite alternate;
}
.loader::before {
left: -20px;
animation-delay: 0s;
}
@keyframes animloader {
0% {
height: 48px;
}
100% {
height: 4px;
}
}
</style>
<script>
export let fullscreen = true;
</script>
{#if fullscreen}
<div class="fixed top-0 flex flex-wrap content-center h-full w-full">
<span class="loader"></span>
</div>
{/if}