Add artifact layer

This commit is contained in:
ernstmul
2025-04-17 10:25:16 +02:00
parent abef8389b2
commit 3f1a279c00
10 changed files with 256 additions and 165 deletions
@@ -7,12 +7,14 @@
IconFolder,
IconSparkles,
IconTemplate,
IconUserGroup
IconUserGroup,
IconViewGrid
} from '@appwrite.io/pink-icons-svelte';
import { base } from '$app/paths';
import { isSmallViewport, isTabletViewport } from '$lib/stores/viewport';
import type { ComponentType } from 'svelte';
import { showChat } from '$lib/stores/chat';
import { page } from '$app/state';
export let project;
export let isOpen;
@@ -20,7 +22,7 @@
const menuItems: Array<
{ type: 'divider' } | { type: 'item'; label: string; path: string; icon: ComponentType }
> = [
{ type: 'item', label: 'Studio', path: 'studio', icon: IconTemplate },
{ type: 'item', label: 'Studio', path: 'studio', icon: IconViewGrid },
{ type: 'divider' },
{ type: 'item', label: 'Auth', path: 'auth', icon: IconUserGroup },
{ type: 'item', label: 'Databases', path: 'databases', icon: IconDatabase },
@@ -37,6 +39,11 @@
{#each menuItems as menuItem}
{#if menuItem.type === 'item'}
<ActionMenu.Item.Anchor
style={`background-color: ${
page.url.pathname.includes(menuItem.path)
? 'var(--overlay-neutral-hover)'
: 'auto'
}`}
href={`${base}/project-${project.$id}/${menuItem.path}`}
leadingIcon={menuItem.icon}
on:click={() => {
+1 -1
View File
@@ -100,7 +100,7 @@
});
$effect(() => {
if ($isSmallViewport || page.url.pathname.endsWith('studio')) {
if ($isSmallViewport || page.url.pathname.includes('artifact-')) {
showChat.set(true);
}
});
@@ -8,6 +8,7 @@ import { isCloud } from '$lib/system';
import type { Organization } from '$lib/stores/organization';
import { defaultRoles, defaultScopes } from '$lib/constants';
import type { Plan } from '$lib/sdk/billing';
import { artifacts } from '$routes/(console)/project-[project]/store';
export const load: LayoutLoad = async ({ params, depends }) => {
depends(Dependencies.PROJECT);
@@ -38,6 +39,25 @@ export const load: LayoutLoad = async ({ params, depends }) => {
}
}
// todo replace with actual artifacts from API
artifacts.set([
{
$id: 'RE1xJXnaCX',
title: 'Dashboard',
url: null
},
{
$id: 'jABosmZQhY',
title: 'Sign in screen',
url: 's-130328439.imagine.dev'
},
{
$id: 'U1aolAia1m',
title: 'Mobile app',
url: null
}
]);
return {
project,
organization,
@@ -44,3 +44,10 @@ function createStats() {
}
export const stats = createStats();
export const artifacts = writable<
Array<{
$id: string;
title: string;
url?: string | null;
}>
>([]);
@@ -1,168 +1,47 @@
<script lang="ts">
import { Layout, Card, Typography, Divider, Icon } from '@appwrite.io/pink-svelte';
import { isTabSelected } from '$lib/helpers/load';
import { page } from '$app/state';
import { Tab, Tabs, Terminal } from '$lib/components';
import { base } from '$app/paths';
import { isSmallViewport } from '$lib/stores/viewport';
<script>
import {
IconChevronDoubleUp,
IconDeviceMobile,
IconExternalLink,
IconRefresh,
IconTerminal
} from '@appwrite.io/pink-icons-svelte';
import { InputText } from '$lib/elements/forms/index.js';
Badge,
Divider,
Icon,
Typography,
Card,
Layout,
Table,
Status
} from '@appwrite.io/pink-svelte';
import { Button } from '$lib/elements/forms';
import { artifacts } from '$routes/(console)/project-[project]/store.js';
import { base } from '$app/paths';
import { page } from '$app/state';
import Placeholder from './assets/placeholder.svg';
const frameUrl = 'https://getbootstrap.com/docs/5.3/examples/blog/';
const projectId = page.params.project;
const path = `${base}/project-${projectId}/studio`;
const tabs = [
{
href: path,
title: 'Preview',
event: 'preview',
hasChildren: true
},
{
href: `${path}/code`,
title: 'Code',
event: 'code',
hasChildren: true
}
];
let terminalOpen = $state(false);
let asideRef;
let isResizing = false;
let terminalHeight = $state(300);
function startResize(event) {
isResizing = true;
window.addEventListener('mousemove', resize);
window.addEventListener('mouseup', stopResize);
window.addEventListener('touchmove', resize);
window.addEventListener('touchend', stopResize);
document.body.style.userSelect = 'none';
document.getElementById('preview-iframe').style.pointerEvents = 'none';
}
function resize(event) {
if (!isResizing) return;
const clientY = event.touches ? event.touches[0].clientY : event.clientY;
const maxHeight = window.innerHeight - 400;
let height =
asideRef.getBoundingClientRect().y -
clientY +
asideRef.getBoundingClientRect().height -
32;
terminalHeight = height < maxHeight ? height : maxHeight;
}
function stopResize() {
isResizing = false;
window.removeEventListener('mousemove', resize);
window.removeEventListener('mouseup', stopResize);
window.removeEventListener('touchmove', resize);
window.removeEventListener('touchend', stopResize);
document.body.style.userSelect = '';
document.getElementById('preview-iframe').style.pointerEvents = '';
}
const projectId = page.data?.project?.$id ?? '';
</script>
<Layout.Stack
direction="column"
height={$isSmallViewport ? 'calc(100vh - 218px)' : 'calc(100vh - 120px)'}
gap="none">
<Layout.Stack direction="column">
<Tabs>
{#each tabs as tab}
<Tab
href={tab.href}
selected={isTabSelected(tab, page.url.pathname, path, tabs)}
event={tab.event}>
{tab.title}
</Tab>
{/each}
</Tabs>
<Divider />
<Layout.Stack direction="row" alignItems="center">
<Icon icon={IconRefresh} color="--fgcolor-neutral-tertiary" />
<InputText id="previewUrl" value={frameUrl} />
<Icon icon={IconDeviceMobile} color="--fgcolor-neutral-tertiary" />
<Icon icon={IconExternalLink} color="--fgcolor-neutral-tertiary" />
</Layout.Stack>
<div></div>
<Layout.Stack>
<Layout.Stack direction="row" justifyContent="space-between" alignItems="center">
<Typography.Text variant="m-500" color="--fgcolor-neutral-secondary"
>Artifacts</Typography.Text>
<Button size="s" on:click={() => {}} event="create_project">Create artifact</Button>
</Layout.Stack>
<div class="iframe-container">
<iframe src={frameUrl} id="preview-iframe"></iframe>
</div>
<div></div>
<aside bind:this={asideRef}>
<details bind:open={terminalOpen}>
<summary
on:mousedown={startResize}
on:touchmove={startResize}
class:terminal-slider={terminalOpen}>
<Layout.Stack direction="row" justify="space-between">
<Layout.Stack direction="row" alignItems="center" gap="xs">
<Icon icon={IconTerminal} color="--fgcolor-neutral-tertiary" />
<Typography.Text>Terminal</Typography.Text>
<Divider />
<Layout.Grid gap="l" columnsS={1} columns={3} columnsL={3} columnsXL={4}>
{#each $artifacts as artifact}
<a href={`${base}/project-${projectId}/studio/artifact-${artifact.$id}`}>
<Card.Base padding="xxs">
<Layout.Stack gap="xs">
<img
src={Placeholder}
alt={`Screenshot of latest ${artifact.title} version`} />
<Typography.Text variant="m-500" color="--fgcolor-neutral-primary"
>{artifact.title}</Typography.Text>
<Status
status={artifact.url ? 'complete' : 'waiting'}
label={artifact.url ?? 'Not released'}></Status>
</Layout.Stack>
<Icon icon={IconChevronDoubleUp} color="--fgcolor-neutral-tertiary" />
</Layout.Stack>
</summary>
<Terminal bind:height={terminalHeight}></Terminal>
</details>
</aside>
</Card.Base></a>
{/each}
</Layout.Grid>
</Layout.Stack>
<style>
aside {
background-color: var(--bgcolor-neutral-default);
margin-inline-start: -25px;
margin-block-end: calc(-1 * var(--space-9));
padding: var(--space-3);
border-bottom-left-radius: var(--border-radius-m);
border-bottom-right-radius: var(--border-radius-m);
border: 1px solid var(--border-neutral);
width: calc(100% - var(--space-7));
position: fixed;
bottom: 116px;
@media (min-width: 768px) {
width: calc(100% + 2 * var(--space-9));
margin-inline-start: calc(-1 * var(--space-9));
position: static;
border: 0;
}
}
summary {
cursor: pointer;
}
.iframe-container {
height: calc(100vh - 296px);
@media (min-width: 768px) {
flex-grow: 1;
height: auto;
}
}
iframe {
border: none;
width: calc(100% + 2 * var(--space-9));
height: 100%;
margin-inline-start: calc(-1 * var(--space-9));
}
.terminal-slider {
cursor: row-resize;
}
</style>
@@ -0,0 +1,168 @@
<script lang="ts">
import { Layout, Card, Typography, Divider, Icon } from '@appwrite.io/pink-svelte';
import { isTabSelected } from '$lib/helpers/load';
import { page } from '$app/state';
import { Tab, Tabs, Terminal } from '$lib/components';
import { base } from '$app/paths';
import { isSmallViewport } from '$lib/stores/viewport';
import {
IconChevronDoubleUp,
IconDeviceMobile,
IconExternalLink,
IconRefresh,
IconTerminal
} from '@appwrite.io/pink-icons-svelte';
import { InputText } from '$lib/elements/forms';
const frameUrl = 'https://getbootstrap.com/docs/5.3/examples/blog/';
const projectId = page.params.project;
const path = `${base}/project-${projectId}/studio`;
const tabs = [
{
href: path,
title: 'Preview',
event: 'preview',
hasChildren: true
},
{
href: `${path}/code`,
title: 'Code',
event: 'code',
hasChildren: true
}
];
let terminalOpen = $state(false);
let asideRef;
let isResizing = false;
let terminalHeight = $state(300);
function startResize(event) {
isResizing = true;
window.addEventListener('mousemove', resize);
window.addEventListener('mouseup', stopResize);
window.addEventListener('touchmove', resize);
window.addEventListener('touchend', stopResize);
document.body.style.userSelect = 'none';
document.getElementById('preview-iframe').style.pointerEvents = 'none';
}
function resize(event) {
if (!isResizing) return;
const clientY = event.touches ? event.touches[0].clientY : event.clientY;
const maxHeight = window.innerHeight - 400;
let height =
asideRef.getBoundingClientRect().y -
clientY +
asideRef.getBoundingClientRect().height -
32;
terminalHeight = height < maxHeight ? height : maxHeight;
}
function stopResize() {
isResizing = false;
window.removeEventListener('mousemove', resize);
window.removeEventListener('mouseup', stopResize);
window.removeEventListener('touchmove', resize);
window.removeEventListener('touchend', stopResize);
document.body.style.userSelect = '';
document.getElementById('preview-iframe').style.pointerEvents = '';
}
</script>
<Layout.Stack
direction="column"
height={$isSmallViewport ? 'calc(100vh - 218px)' : 'calc(100vh - 120px)'}
gap="none">
<Layout.Stack direction="column">
<Tabs>
{#each tabs as tab}
<Tab
href={tab.href}
selected={isTabSelected(tab, page.url.pathname, path, tabs)}
event={tab.event}>
{tab.title}
</Tab>
{/each}
</Tabs>
<Divider />
<Layout.Stack direction="row" alignItems="center">
<Icon icon={IconRefresh} color="--fgcolor-neutral-tertiary" />
<InputText id="previewUrl" value={frameUrl} />
<Icon icon={IconDeviceMobile} color="--fgcolor-neutral-tertiary" />
<Icon icon={IconExternalLink} color="--fgcolor-neutral-tertiary" />
</Layout.Stack>
<div></div>
</Layout.Stack>
<div class="iframe-container">
<iframe src={frameUrl} id="preview-iframe"></iframe>
</div>
<div></div>
<aside bind:this={asideRef}>
<details bind:open={terminalOpen}>
<summary
on:mousedown={startResize}
on:touchmove={startResize}
class:terminal-slider={terminalOpen}>
<Layout.Stack direction="row" justify="space-between">
<Layout.Stack direction="row" alignItems="center" gap="xs">
<Icon icon={IconTerminal} color="--fgcolor-neutral-tertiary" />
<Typography.Text>Terminal</Typography.Text>
</Layout.Stack>
<Icon icon={IconChevronDoubleUp} color="--fgcolor-neutral-tertiary" />
</Layout.Stack>
</summary>
<Terminal bind:height={terminalHeight}></Terminal>
</details>
</aside>
</Layout.Stack>
<style>
aside {
background-color: var(--bgcolor-neutral-default);
margin-inline-start: -25px;
margin-block-end: calc(-1 * var(--space-9));
padding: var(--space-3);
border-bottom-left-radius: var(--border-radius-m);
border-bottom-right-radius: var(--border-radius-m);
border: 1px solid var(--border-neutral);
width: calc(100% - var(--space-7));
position: fixed;
bottom: 116px;
@media (min-width: 768px) {
width: calc(100% + 2 * var(--space-9));
margin-inline-start: calc(-1 * var(--space-9));
position: static;
border: 0;
}
}
summary {
cursor: pointer;
}
.iframe-container {
height: calc(100vh - 296px);
@media (min-width: 768px) {
flex-grow: 1;
height: auto;
}
}
iframe {
border: none;
width: calc(100% + 2 * var(--space-9));
height: 100%;
margin-inline-start: calc(-1 * var(--space-9));
}
.terminal-slider {
cursor: row-resize;
}
</style>
@@ -4,7 +4,7 @@
import Filesystem from '$lib/components/editor/filesystem.svelte';
import { Layout } from '@appwrite.io/pink-svelte';
import html from '../../../../../app.html?raw';
import html from '../../../../../../app.html?raw';
import js from './app.js?raw';
import css from './app.css?raw';
@@ -0,0 +1,10 @@
<svg width="300" height="146" viewBox="0 0 300 146" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M0.5 12.8C0.5 10.5515 0.500389 8.89527 0.607333 7.58633C0.7138 6.28324 0.923378 5.36848 1.31745 4.59507C2.0365 3.18386 3.18386 2.0365 4.59507 1.31745C5.36848 0.923378 6.28324 0.7138 7.58633 0.607333C8.89526 0.500389 10.5515 0.5 12.8 0.5H287.2C289.448 0.5 291.105 0.500389 292.414 0.607333C293.717 0.7138 294.632 0.923377 295.405 1.31745C296.816 2.0365 297.964 3.18386 298.683 4.59507C299.077 5.36848 299.286 6.28324 299.393 7.58633C299.5 8.89526 299.5 10.5515 299.5 12.8V133.2C299.5 135.448 299.5 137.105 299.393 138.414C299.286 139.717 299.077 140.632 298.683 141.405C297.964 142.816 296.816 143.964 295.405 144.683C294.632 145.077 293.717 145.286 292.414 145.393C291.105 145.5 289.448 145.5 287.2 145.5H12.8C10.5515 145.5 8.89526 145.5 7.58633 145.393C6.28323 145.286 5.36848 145.077 4.59507 144.683L4.36808 145.128L4.59507 144.683C3.18386 143.964 2.0365 142.816 1.31745 141.405C0.923377 140.632 0.7138 139.717 0.607333 138.414C0.500389 137.105 0.5 135.448 0.5 133.2V12.8Z" fill="url(#pattern0_878_4602)"/>
<path d="M0.5 12.8C0.5 10.5515 0.500389 8.89527 0.607333 7.58633C0.7138 6.28324 0.923378 5.36848 1.31745 4.59507C2.0365 3.18386 3.18386 2.0365 4.59507 1.31745C5.36848 0.923378 6.28324 0.7138 7.58633 0.607333C8.89526 0.500389 10.5515 0.5 12.8 0.5H287.2C289.448 0.5 291.105 0.500389 292.414 0.607333C293.717 0.7138 294.632 0.923377 295.405 1.31745C296.816 2.0365 297.964 3.18386 298.683 4.59507C299.077 5.36848 299.286 6.28324 299.393 7.58633C299.5 8.89526 299.5 10.5515 299.5 12.8V133.2C299.5 135.448 299.5 137.105 299.393 138.414C299.286 139.717 299.077 140.632 298.683 141.405C297.964 142.816 296.816 143.964 295.405 144.683C294.632 145.077 293.717 145.286 292.414 145.393C291.105 145.5 289.448 145.5 287.2 145.5H12.8C10.5515 145.5 8.89526 145.5 7.58633 145.393C6.28323 145.286 5.36848 145.077 4.59507 144.683L4.36808 145.128L4.59507 144.683C3.18386 143.964 2.0365 142.816 1.31745 141.405C0.923377 140.632 0.7138 139.717 0.607333 138.414C0.500389 137.105 0.5 135.448 0.5 133.2V12.8Z" stroke="#EDEDF0"/>
<defs>
<pattern id="pattern0_878_4602" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0_878_4602" transform="matrix(0.00390625 0 0 0.00802654 0 -0.527397)"/>
</pattern>
<image id="image0_878_4602" width="256" height="256" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAAAXNSR0IArs4c6QAACixJREFUeF7t3TFSJEAMQ9HhBNz/jESkJLuH+EGXym9zirKxvmUx9H79/f39+4R/v7+/4as/n+/v7/T1vr/+lwG6Pn9fAABARUAAvA1gAOBAiv4/AAAAaYCuWzD1c2BFQBXAHAAHUOaPAxjPwAAAAAAgdKBu4NcOEAAAIIz/hwPgALZDkNcE9v1lAIXA1YFwABxAmT8OgAPgAIqCOAAOoMwPBzBOYAAAAAAIHagEJEACDOM3fwLJAGQAZf7nBXB9AQAAAABA6MC6AwUAAAjj73MAACCESwK6bkHV/zaD+fr5+UnvAfgBvv0B6r/+lw0EABxMmR8PuoyfkAAAAAAQOrDuwAAAAML4e9INAMYt0HqKuz6A+v/2o/QcAAfAAYQOrAMYAAAgjL8TAACcAElALPBbC3y9/xwAB5AAtr4BAcAHgQggdAAAtj+IxAFwAEH+MoB1AAIAAABA6AAACAHD+Phruus3+Ov6OQAOIAFsfQO+FuDr7w8AAAAAoQPrAAQAAAjjLwScB4D/Hnz71zivLaTvv/1BJk+CCTGTAwAAAEgDtG6hCGBbANfnjwPgABLAAXAbgAAAAAAQOrAOQAAAgDD+PsgEAH6NlgR0/QZV/9vfQnEAHEAC2PoGvA4gAAAAAAgdWAcgAABAGH8ZAADIAJKArltQ9csAkoDWCUwAbwVwvf9OACcAAIcOrC8gAACAMP4yAACQASQBXbeg6n97AnEAHEAC2PoGvA4gD4JwMAkA1wW0Xj8AAAAAhA4AAAsdxkeI5oR4++fEHAAHkAC2vgGvAwgAAAAAQgfWAQgAABDG36vAACADSAK6bkHVLwNIAlonMAG8FcD1/jsBnAAAHDqwvoAAAADC+MsAAEAGkAR03YKq/+0JxAFwAAlg6xvwOoAAAAAAIHRgHYAAAABh/GUAACADSAK6bkHVLwNIAlonMAG8FcD1/nsQhINJAL4uoPX6AQAAACB0AACEaGF8hGhOOG8CJgGtE5gA3grgev+dAE4AAA4dWF9AAAAAYfw9aQYAMoAkoOsWVP1vTyAOgANIAFvfgNcBBAAAAAChA+sABAAACOMvAwAAGUAS0HULqn4ZQBLQOoEJ4K0ArvffCeAEAODQgfUFBAAAEMZfBgAAMoAkoOsWVP1vTyAOgANIAFvfgNcB5EkwDiYB4LqA1usHAAAAgNABAGChw/gI0ZwQb59E4wA4gASw9Q14HUAAAAAAEDqwDkAAAIAw/p40AwAZQBLQdQuqfhlAEtA6gQngrQCu998J4AQA4NCB9QUEAAAQxl8GAAAygCSg6xZU/W9PIA6AA0gAW9+A1wEEAAAAAKED6wAEAAAI4y8DAAAZQBLQdQuqfhlAEtA6gQngrQCu99+DIBxMAvB1Aa3XDwAAAAChAwAgRAvjI0RzwnkTMAloncAE8FYA1/vvBHACAHDowPoCAgAACOPvSTMAkAEkAV23oOp/ewJxABxAAtj6BrwOIAAAAAAIHVgHIAAAQBh/GQAAyACSgK5bUPXLAJKA1glMAG8FcL3/TgAnAACHDqwvIAAAgDD+MgAAkAEkAV23oOp/ewJxABxAAtj6BrwOIE+CcTAJANcFtF4/AAAAAIQOAAALHcZHiOaEePskGgfAASSArW/A6wACAAAAgNCBdQACAACE8fekGQDIAJKArltQ9csAkoDWCUwAbwVwvf9OACcAAIcOrC8gAACAMP4yAACQASQBXbeg6n97AnEAHEAC2PoGvA4gAAAAAAgdWAcgAABAGH8ZAADIAJKArltQ9csAkoDWCUwAbwVwvf8eBOFgEoCvC2i9fgAAAAAIHQAAIVoYHyGaE86bgElA6wQmgLcCuN5/J4ATAIBDB9YXEAAAQBh/T5oBgAwgCei6BVX/2xOIA+AAEsDWN+B1AAEAAABA6MA6AAEAAML4ywAAQAaQBHTdgqpfBpAEtE5gAngrgOv9dwI4AQA4dGB9AQEAAITxlwEAgAwgCei6BVX/2xOIA+AAEsDWN+B1AHkSjINJALguoPX6AQAAACB0AABY6DA+QjQnxNsn0TgADiABbH0DXgcQAAAAAIQOrAMQAAAgjL8nzQBABpAEdN2Cql8GkAS0TmACeCuA6/13AjgBADh0YH0BAQAAhPGXAQCADCAJ6LoFVf/bE4gD4AASwNY34HUAAQAAAEDowDoAAQAAwvjLAABABpAEdN2Cql8GkAS0TmACeCuA6/33IAgHkwB8XUDr9QMAAABA6AAACNHC+AjRnHDeBEwCWicwAbwVwPX+OwGcAAAcOrC+gAAAAML4e9IMAGQASUDXLaj6355AHAAHkAC2vgGvAwgAAAAAQgfWAQgAABDGXwYAADKAJKDrFlT9MoAkoHUCE8BbAVzvvxPACQDAoQPrCwgAACCMvwwAAGQASUDXLaj6355AHAAHkAC2vgGvA8iTYBxMAsB1Aa3XDwAAAAChAwDAQofxEaI5Id4+icYBcAAJYOsb8DqAAAAAACB0YB2AAAAAYfw9aQYAMoAkoOsWVP0ygCSgdQITwFsBXO+/E8AJAMChA+sLCAAAIIy/DAAAZABJQNctqPrfnkAcAAeQALa+Aa8DCAAAAABCB9YBCAAAEMZfBgAAMoAkoOsWVP0ygCSgdQITwFsBXO+/B0E4mATg6wJarx8AAAAAQgcAQIgWxkeI5oTzJmAS0DqBCeCtAK733wngBADg0IH1BQQAABDG35NmACADSAK6bkHV//YE4gA4gASw9Q14HUAAAAAAEDqwDkAAAIAw/jIAAJABJAFdt6DqlwEkAa0TmADeCuB6/50ATgAADh1YX0AAAABh/GUAACADSAK6bkHV//YE4gA4gASw9Q14HUCeBONgEgCuC2i9fgAAAAAIHQAAFjqMjxDNCfH2STQOgANIAFvfgNcBBAAAAAChA+sABAAACOPvSTMAkAEkAV23oOqXASQBrROYAN4K4Hr/nQBOAAAOHVhfQAAAAGH8ZQAAIANIArpuQdX/9gTiADiABLD1DXgdQAAAAAAQOrAOQAAAgDD+MgAAkAEkAV23oOqXASQBrROYAN4K4Hr/PQjCwSQAXxfQev0AAAAAEDoAAEK0MD5CNCecNwGTgNYJTABvBXC9/04AJwAAhw6sLyAAAIAw/p40AwAZQBLQdQuq/rcnEAfAASSArW/A6wACAAAAgNCBdQACAACE8ZcBAIAMIAnougVVvwwgCWidwATwVgDX++8EcAIAcOjA+gICAAAI4y8DAAAZQBLQdQuq/rcnEAfAASSArW/A6wDyJBgHkwBwXUDr9QMAAABA6AAAsNBhfIRoToi3T6JxABxAAtj6BrwOIAAAAAAIHVgHIAAAQBh/T5oBgAwgCei6BVW/DCAJaJ3ABPBWANf77wRwAgBw6MD6AgIAAAjjLwMAABlAEtB1C6r+tycQB8ABJICtb8DrAAIAAACA0IF1AAIAAITxlwEAgAwgCei6BVW/DCAJaJ3ABPBWANf7/x/aVlkHhH7qqQAAAABJRU5ErkJggg=="/>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB