This commit is contained in:
Torsten Dittmann
2022-09-06 13:28:14 +02:00
163 changed files with 2161 additions and 495 deletions
+21
View File
@@ -0,0 +1,21 @@
<script lang="ts">
import Avatar from './avatar.svelte';
export let avatars = [];
export let total = avatars.length;
export let size = 40;
</script>
<ul class="avatars-group">
{#each avatars as av, index}
{#if index < 2}
<li class="avatars-group-item">
<Avatar {size} src={av.img} name={av.name} />
</li>
{/if}
{/each}
{#if total > 2}
<li class="avatars-group-item">
<div class="avatar">+{total - 2}</div>
</li>
{/if}
</ul>
+5 -1
View File
@@ -6,6 +6,7 @@
export let horizontal: 'left' | 'right' = 'right';
export let arrowPosition: 'start' | 'center' | 'end' = 'start';
export let arrow = true;
export let scrollable = false;
let parentElement: HTMLDivElement;
const onBlur = (event: MouseEvent) => {
@@ -31,7 +32,10 @@
class:is-block-end={position === 'bottom'}
class:is-inline-end={horizontal === 'left'}
transition:slide={{ duration: 100 }}>
<section class="drop-section">
<section
class:u-overflow-y-auto={scrollable}
class:u-max-height-200={scrollable}
class="drop-section ">
<ul class="drop-list">
<slot name="list" />
</ul>
+1 -1
View File
@@ -3,7 +3,7 @@
export let icon: string = null;
</script>
<li class="drop-list-item">
<li class="drop-list-item" on:click>
<a {href} class="drop-button">
<span class="text"><slot /></span>
{#if icon}
+1
View File
@@ -19,6 +19,7 @@ export { default as Collapsible } from './collapsible.svelte';
export { default as DropTabs } from './dropTabs.svelte';
export { default as DropTabsItem } from './dropTabsItem.svelte';
export { default as Avatar } from './avatar.svelte';
export { default as AvatarGroup } from './avatarGroup.svelte';
export { default as Alert } from './alert.svelte';
export { default as Box } from './box.svelte';
export { default as Search } from './search.svelte';
+15 -10
View File
@@ -8,6 +8,7 @@
export let size: 'small' | 'big' = null;
export let warning = false;
export let error: string = null;
export let closable = true;
const dispatch = createEventDispatcher();
const transitionFly: FlyParams = {
@@ -31,8 +32,10 @@
}
};
const closeModal = () => {
show = false;
dispatch('close');
if (closable) {
show = false;
dispatch('close');
}
};
/**
@@ -65,14 +68,16 @@
<h4 class="heading-level-5">
<slot name="header" />
</h4>
<button
type="button"
class="x-button"
aria-label="Close Modal"
title="Close Modal"
on:click={closeModal}>
<span class="icon-x" aria-hidden="true" />
</button>
{#if closable}
<button
type="button"
class="x-button"
aria-label="Close Modal"
title="Close Modal"
on:click={closeModal}>
<span class="icon-x" aria-hidden="true" />
</button>
{/if}
</header>
<div class="modal-content">
{#if error}
+4 -1
View File
@@ -7,6 +7,7 @@
export let round = false;
export let external = false;
export let href: string = null;
export let fullWidth = false;
//TODO: add option to add aria-label to buttons that are only icons
</script>
@@ -20,7 +21,8 @@
class:is-only-icon={round}
class:is-secondary={secondary}
class:is-text={text}
class:is-danger={danger}>
class:is-danger={danger}
class:is-full-width={fullWidth}>
<slot />
</a>
{:else}
@@ -32,6 +34,7 @@
class:is-secondary={secondary}
class:is-danger={danger}
class:is-text={text}
class:is-full-width={fullWidth}
type={submit ? 'submit' : 'button'}>
<slot />
</button>
+284
View File
@@ -0,0 +1,284 @@
<svg width="600" height="400" viewBox="0 0 600 400" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_129_12217)">
<path d="M10 173.533L153.942 258L306 171.379L162.912 77L10 173.533Z" fill="url(#paint0_linear_129_12217)"/>
<path d="M218 243.774L362.531 325L420 292.164L278.471 201L218 243.774Z" fill="url(#paint1_linear_129_12217)"/>
<path d="M153 257.818V138.165C153 134.18 155.145 130.498 158.623 128.512L302.704 46.2306C303.854 45.5738 305.289 46.3982 305.289 47.7157V170.646L390.326 221.35C392.527 222.663 392.565 225.818 390.395 227.182L253.165 313.469C252.078 314.152 250.698 314.178 249.586 313.536L153 257.818Z" fill="url(#paint2_linear_129_12217)"/>
<path d="M250.687 307L158 253.842L304.754 170L388 219.268L380.276 224.886L352.384 243.47L250.687 307Z" fill="url(#paint3_linear_129_12217)"/>
<path d="M234.034 288.505L186 259.6L310.973 188L353.332 213.152C355.549 214.469 355.558 217.646 353.347 218.974L237.602 288.506C236.505 289.165 235.13 289.164 234.034 288.505Z" fill="url(#paint4_linear_129_12217)"/>
<path d="M158 255V139.683C158 136.258 159.832 133.1 162.793 131.421L302.453 52.2238C303.592 51.5777 305 52.4078 305 53.7259V170.554L158 255Z" fill="url(#paint5_linear_129_12217)"/>
<path d="M173 213.589V150.081C173 148.241 173.997 146.543 175.61 145.636L279.437 87.2241C280.581 86.5803 282 87.4004 282 88.7056V155.341C282 156.561 281.343 157.687 280.278 158.294L178.144 216.542C175.855 217.847 173 216.208 173 213.589Z" fill="url(#paint6_linear_129_12217)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M335 185.747L183.431 274L183 273.253L334.569 185L335 185.747Z" fill="url(#paint7_radial_129_12217)" fill-opacity="0.2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M344 192.747L191.434 281L191 280.253L343.566 192L344 192.747Z" fill="url(#paint8_radial_129_12217)" fill-opacity="0.2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M352 197.738L200.431 285L200 284.262L351.569 197L352 197.738Z" fill="url(#paint9_radial_129_12217)" fill-opacity="0.2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M359 203.747L209.426 292L209 291.253L358.574 203L359 203.747Z" fill="url(#paint10_radial_129_12217)" fill-opacity="0.2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M250.594 279L202 252.763L202.406 252L251 278.237L250.594 279Z" fill="url(#paint11_radial_129_12217)" fill-opacity="0.2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M263.588 271L215 245.74L215.412 245L264 270.26L263.588 271Z" fill="url(#paint12_radial_129_12217)" fill-opacity="0.2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M339.594 228L291 201.763L291.406 201L340 227.237L339.594 228Z" fill="url(#paint13_radial_129_12217)" fill-opacity="0.2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M352.596 220L305 193.769L305.404 193L353 219.231L352.596 220Z" fill="url(#paint14_radial_129_12217)" fill-opacity="0.2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M266.6 258L229 237.746L229.4 237L267 257.254L266.6 258Z" fill="url(#paint15_radial_129_12217)" fill-opacity="0.2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M279.59 250L241 230.711L241.41 230L280 249.289L279.59 250Z" fill="url(#paint16_radial_129_12217)" fill-opacity="0.2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M290.6 244L253 222.782L253.4 222L291 243.218L290.6 244Z" fill="url(#paint17_radial_129_12217)" fill-opacity="0.2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M303.568 237L263 215.782L263.432 215L304 236.218L303.568 237Z" fill="url(#paint18_radial_129_12217)" fill-opacity="0.2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M315.6 230L278 208.782L278.4 208L316 229.218L315.6 230Z" fill="url(#paint19_radial_129_12217)" fill-opacity="0.2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M465.141 239.16V179H466V239.16C466 241.786 464.578 244.208 462.28 245.496L370.422 297L370 296.255L461.859 244.75C463.886 243.614 465.141 241.477 465.141 239.16Z" fill="url(#paint20_radial_129_12217)" fill-opacity="0.6"/>
<path d="M187 263.552V260.534L236.798 288.552L357 217V220.448L236.798 292L187 263.552Z" fill="url(#paint21_linear_129_12217)"/>
<path d="M361 217.238C361 216.001 361.668 214.86 362.749 214.252L422.877 180.447C425.167 179.159 428 180.81 428 183.432V284.922C428 287.369 426.692 289.631 424.567 290.856L366.155 324.535C363.865 325.856 361 324.207 361 321.568V217.238Z" fill="url(#paint22_linear_129_12217)"/>
<path d="M364 220.038C363.989 218.787 364.662 217.629 365.758 217.012L420.407 186.227C421.565 185.575 423 186.405 423 187.725V282.259C423 283.479 422.351 284.607 421.292 285.227L367.442 316.758C366.291 317.433 364.836 316.616 364.825 315.29L364 220.038Z" fill="url(#paint23_linear_129_12217)"/>
<path d="M373 253.14V225.174C373 224.549 373.338 223.973 373.883 223.671L412.733 202.108C413.302 201.792 414 202.206 414 202.86V229.713C414 230.325 413.676 230.891 413.15 231.198L374.283 253.883C373.714 254.215 373 253.802 373 253.14Z" fill="url(#paint24_linear_129_12217)"/>
<path d="M373 268V263.339L414 240V244.349L373 268Z" fill="url(#paint25_linear_129_12217)"/>
<path d="M373 275.168V272.547C373 272.254 373.167 271.982 373.439 271.832L405.649 254.117C406.246 253.789 407 254.188 407 254.832V257.163C407 257.455 406.836 257.725 406.567 257.875L374.356 275.88C373.76 276.213 373 275.814 373 275.168Z" fill="url(#paint26_linear_129_12217)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M350.379 64L431 106.214L430.621 107L350 64.7858L350.379 64Z" fill="url(#paint27_radial_129_12217)" fill-opacity="0.6"/>
<path d="M438 82.4701C438 79.8793 440.758 78.2046 443.08 79.3855L477.101 96.6878C478.267 97.2806 479 98.4718 479 99.7725V191.53C479 194.128 476.227 195.802 473.905 194.607L439.884 177.091C438.726 176.496 438 175.309 438 174.015V82.4701Z" fill="url(#paint28_linear_129_12217)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M447.249 86.3945L439 82V168.114C439 169.373 439.674 170.533 440.761 171.146L469.904 187.557C472.19 188.844 475 187.172 475 184.525V103.272C475 101.984 474.295 100.802 473.168 100.202L467.554 97.2114L467.633 98.8586C467.665 99.5272 466.968 99.9788 466.381 99.67L447.843 89.9166C447.573 89.7742 447.397 89.4971 447.382 89.1888L447.249 86.3945Z" fill="url(#paint29_linear_129_12217)"/>
<path d="M470 140.151V112.523C470 111.881 469.637 111.293 469.062 111.006L443.228 98.0907C442.664 97.8086 442 98.2187 442 98.8491V125.406C442 126.029 442.341 126.601 442.889 126.898L468.747 140.896C469.313 141.203 470 140.793 470 140.151Z" fill="url(#paint30_linear_129_12217)"/>
<path d="M470 154V149.193L442 133V137.485L470 154Z" fill="url(#paint31_linear_129_12217)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M282.856 95V291.68C282.856 296.714 288.341 299.806 292.619 297.186L342.554 266.594L343 267.328L293.065 297.92C288.216 300.89 282 297.385 282 291.68V95H282.856Z" fill="url(#paint32_radial_129_12217)" fill-opacity="0.6"/>
<path d="M183.58 201.297C185.281 197.918 183.58 189.262 188.318 182.586C189.31 181.187 194.053 190.383 193.895 187.113C193.737 183.844 197.334 174.219 200.342 172.5C201.688 171.731 202.061 175.939 202.491 175.939C202.491 175.939 204.234 158.747 208.078 158.747C208.508 158.747 208.508 163.474 208.938 163.475C209.368 163.475 211.517 154.449 214.525 154.449C214.955 154.449 218.199 161.765 219.683 162.615C222.049 156.701 225.38 162.814 226.356 163.449L226.56 163.475C232.577 157.811 236.445 169.062 236.445 169.062L183.58 201.297Z" fill="url(#paint33_linear_129_12217)"/>
<mask id="mask0_129_12217" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="193" y="71" width="108" height="132">
<path d="M193 199.536V135.051C193 133.183 193.988 131.46 195.586 130.538L298.46 71.2275C299.594 70.5739 301 71.4066 301 72.7318V140.393C301 141.631 300.349 142.774 299.294 143.391L198.097 202.535C195.829 203.86 193 202.196 193 199.536Z" fill="white"/>
</mask>
<g mask="url(#mask0_129_12217)">
<path d="M247.131 126.667L250.131 125V162.5L247.131 165V126.667Z" fill="url(#paint34_linear_129_12217)"/>
<path d="M252.131 139.655L255.131 138V159.517L252.131 162V139.655Z" fill="url(#paint35_linear_129_12217)"/>
<path d="M262.131 132.724L265.131 131V153.414L262.131 156V132.724Z" fill="url(#paint36_linear_129_12217)"/>
<path d="M267.131 128.793L270.131 127V150.31L267.131 153V128.793Z" fill="url(#paint37_linear_129_12217)"/>
<path d="M272.131 136.966L275.131 136V148.552L272.131 150V136.966Z" fill="url(#paint38_linear_129_12217)"/>
<path d="M257 126.744L260 125V156.385L257 159V126.744Z" fill="url(#paint39_linear_129_12217)"/>
</g>
<path d="M181 152.019L212 135V139.981L181 157V152.019Z" fill="url(#paint40_linear_129_12217)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M122.675 167.304L11 98.7355L11.4477 98L123.123 166.569C127.824 169.455 127.765 176.334 123.014 179.138L59.7078 216.503C55.4736 219.002 55.4731 225.151 59.7069 227.651L307.585 374.008C309.56 375.174 312.002 375.198 314 374.071L439.269 303.399C441.548 302.113 444.337 302.15 446.581 303.495L638 418.26L637.56 419L446.142 304.236C444.161 303.048 441.7 303.016 439.69 304.15L314.42 374.823C312.156 376.1 309.388 376.072 307.15 374.751L59.2719 228.394C54.4737 225.561 54.4742 218.592 59.273 215.759L122.579 178.395C126.771 175.921 126.824 169.851 122.675 167.304Z" fill="url(#paint41_radial_129_12217)"/>
<path d="M282 196.401L299 186V206.498L282 217V196.401Z" fill="url(#paint42_linear_129_12217)"/>
<path d="M282 196.401L265 186V206.498L282 217V196.401Z" fill="url(#paint43_linear_129_12217)"/>
<path d="M265 186L281.854 176L299 186L282 196.5L265 186Z" fill="url(#paint44_linear_129_12217)"/>
<path d="M296.501 41.9936L317 29.8677V53.7664L296.501 66.01V41.9936Z" fill="url(#paint45_linear_129_12217)"/>
<path d="M296.501 41.9936L276.003 29.8677V53.7664L296.501 66.01V41.9936Z" fill="url(#paint46_linear_129_12217)"/>
<path d="M276 29.9017L296.322 18L316.997 29.9017L296.322 42.2747L276 29.9017Z" fill="url(#paint47_linear_129_12217)"/>
<path d="M343.042 77.4135L351.085 72.6561V82.0323L343.042 86.8359V77.4135Z" fill="url(#paint48_linear_129_12217)"/>
<path d="M343.042 77.4135L335 72.6561V82.0323L343.042 86.8359V77.4135Z" fill="url(#paint49_linear_129_12217)"/>
<path d="M335 72.6695L342.974 68.0001L351.085 72.6695L342.974 77.5239L335 72.6695Z" fill="url(#paint50_linear_129_12217)"/>
<path d="M407.741 32.6788L411.166 30.653V34.6457L407.741 36.6913V32.6788Z" fill="url(#paint51_linear_129_12217)"/>
<path d="M407.741 32.6788L404.316 30.653V34.6457L407.741 36.6913V32.6788Z" fill="url(#paint52_linear_129_12217)"/>
<path d="M404.316 30.6586L407.712 28.6702L411.166 30.6586L407.712 32.7258L404.316 30.6586Z" fill="url(#paint53_linear_129_12217)"/>
</g>
<defs>
<linearGradient id="paint0_linear_129_12217" x1="219.72" y1="247.226" x2="126.879" y2="179.065" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#F02E65" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint1_linear_129_12217" x1="433.724" y1="331.913" x2="347.918" y2="267.283" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#F02E65" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint2_linear_129_12217" x1="-344.968" y1="220.356" x2="699.378" y2="354.525" gradientUnits="userSpaceOnUse">
<stop stop-color="#3E435A"/>
<stop offset="1" stop-color="#3C4158"/>
</linearGradient>
<linearGradient id="paint3_linear_129_12217" x1="383" y1="158" x2="52.5" y2="299.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#1B1B28"/>
<stop offset="1" stop-color="#282A3B" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint4_linear_129_12217" x1="294.5" y1="238" x2="201" y2="327.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#373B4D"/>
<stop offset="1" stop-color="#373B4D" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint5_linear_129_12217" x1="424.5" y1="65.5" x2="17.3698" y2="339.823" gradientUnits="userSpaceOnUse">
<stop stop-color="#1B1B28"/>
<stop offset="1" stop-color="#373B4D"/>
</linearGradient>
<linearGradient id="paint6_linear_129_12217" x1="170.425" y1="205.425" x2="383.489" y2="101.071" gradientUnits="userSpaceOnUse">
<stop stop-color="#373B4D"/>
<stop offset="1" stop-color="#2C3041"/>
</linearGradient>
<radialGradient id="paint7_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(259 229.5) rotate(90) scale(44.1266 75.7844)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint8_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(267.5 236.5) rotate(90) scale(44.1266 76.283)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint9_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(276 241) rotate(90) scale(43.6308 75.7844)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint10_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(284 247.5) rotate(90) scale(44.1266 74.7872)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint11_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(226.5 265.5) rotate(90) scale(13.1183 24.2972)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint12_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(239.5 258) rotate(90) scale(12.63 24.2939)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint13_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(315.5 214.5) rotate(90) scale(13.1183 24.2972)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint14_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(329 206.5) rotate(90) scale(13.1157 23.7981)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint15_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(248 247.5) rotate(90) scale(10.1268 18.8)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint16_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(260.5 240) rotate(90) scale(9.64456 19.2948)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint17_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(272 233) rotate(90) scale(10.609 18.8)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint18_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(283.5 226) rotate(90) scale(10.609 20.2842)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint19_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(297 219) rotate(90) scale(10.609 18.8)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint20_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(473.302 237.6) rotate(145.202) scale(50.2171 40.4795)">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#F02E65" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint21_linear_129_12217" x1="193.5" y1="347.5" x2="668.828" y2="138.887" gradientUnits="userSpaceOnUse">
<stop stop-color="#282A3B"/>
<stop offset="1" stop-color="#2E3453"/>
</linearGradient>
<linearGradient id="paint22_linear_129_12217" x1="412.538" y1="138.582" x2="397.582" y2="333.082" gradientUnits="userSpaceOnUse">
<stop stop-color="#292D44"/>
<stop offset="1" stop-color="#373B4D"/>
</linearGradient>
<linearGradient id="paint23_linear_129_12217" x1="412.585" y1="126.195" x2="421.125" y2="332.925" gradientUnits="userSpaceOnUse">
<stop stop-color="#25283C"/>
<stop offset="1" stop-color="#282A3B"/>
</linearGradient>
<linearGradient id="paint24_linear_129_12217" x1="373" y1="236.174" x2="431.929" y2="221.119" gradientUnits="userSpaceOnUse">
<stop stop-color="#34384A"/>
<stop offset="1" stop-color="#454B5D"/>
</linearGradient>
<linearGradient id="paint25_linear_129_12217" x1="373" y1="240" x2="435.332" y2="266.182" gradientUnits="userSpaceOnUse">
<stop stop-color="#373B4D"/>
<stop offset="1" stop-color="#333A56"/>
</linearGradient>
<linearGradient id="paint26_linear_129_12217" x1="365.395" y1="276.638" x2="438.324" y2="274.214" gradientUnits="userSpaceOnUse">
<stop stop-color="#373B4D"/>
<stop offset="1" stop-color="#373B4D"/>
</linearGradient>
<radialGradient id="paint27_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(395.354 82.4219) rotate(90) scale(24.1852 46.1891)">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#F02E65" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint28_linear_129_12217" x1="506.043" y1="-487.649" x2="460.435" y2="247.086" gradientUnits="userSpaceOnUse">
<stop stop-color="#2D3147"/>
<stop offset="1" stop-color="#34384B"/>
</linearGradient>
<linearGradient id="paint29_linear_129_12217" x1="391" y1="-559.887" x2="466.038" y2="267.468" gradientUnits="userSpaceOnUse">
<stop stop-color="#282A3B"/>
<stop offset="1" stop-color="#282A3B"/>
</linearGradient>
<linearGradient id="paint30_linear_129_12217" x1="484.424" y1="133.942" x2="432.5" y2="133.847" gradientUnits="userSpaceOnUse">
<stop stop-color="#4F5769"/>
<stop offset="1" stop-color="#373B4D"/>
</linearGradient>
<linearGradient id="paint31_linear_129_12217" x1="470" y1="125.125" x2="407.406" y2="150.451" gradientUnits="userSpaceOnUse">
<stop stop-color="#373B4D"/>
<stop offset="1" stop-color="#383F5E"/>
</linearGradient>
<radialGradient id="paint32_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(228.927 264.381) rotate(-41.8532) scale(239.041 92.135)">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#F02E65" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint33_linear_129_12217" x1="198.756" y1="161.95" x2="211.336" y2="187.777" gradientUnits="userSpaceOnUse">
<stop stop-color="#4F5769"/>
<stop offset="1" stop-color="#373B4D"/>
</linearGradient>
<linearGradient id="paint34_linear_129_12217" x1="248.631" y1="125" x2="248.631" y2="165" gradientUnits="userSpaceOnUse">
<stop stop-color="#4A5163"/>
<stop offset="1" stop-color="#3F4456"/>
</linearGradient>
<linearGradient id="paint35_linear_129_12217" x1="253.631" y1="138" x2="253.631" y2="162" gradientUnits="userSpaceOnUse">
<stop stop-color="#4A5163"/>
<stop offset="1" stop-color="#3F4456"/>
</linearGradient>
<linearGradient id="paint36_linear_129_12217" x1="263.631" y1="131" x2="263.631" y2="156" gradientUnits="userSpaceOnUse">
<stop stop-color="#4A5163"/>
<stop offset="1" stop-color="#3F4456"/>
</linearGradient>
<linearGradient id="paint37_linear_129_12217" x1="268.631" y1="127" x2="268.631" y2="153" gradientUnits="userSpaceOnUse">
<stop stop-color="#4A5163"/>
<stop offset="1" stop-color="#3F4456"/>
</linearGradient>
<linearGradient id="paint38_linear_129_12217" x1="273.631" y1="136" x2="273.631" y2="150" gradientUnits="userSpaceOnUse">
<stop stop-color="#4A5163"/>
<stop offset="1" stop-color="#3F4456"/>
</linearGradient>
<linearGradient id="paint39_linear_129_12217" x1="258.5" y1="125" x2="258.5" y2="159" gradientUnits="userSpaceOnUse">
<stop stop-color="#4A5163"/>
<stop offset="1" stop-color="#3F4456"/>
</linearGradient>
<linearGradient id="paint40_linear_129_12217" x1="163.347" y1="162.396" x2="216.261" y2="156.595" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#F02E65" stop-opacity="0"/>
</linearGradient>
<radialGradient id="paint41_radial_129_12217" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(201.766 312.594) rotate(29.046) scale(310.731 612.014)">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#F02E65" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint42_linear_129_12217" x1="339.926" y1="175.17" x2="289.175" y2="215.325" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#F02E65" stop-opacity="0.53"/>
</linearGradient>
<linearGradient id="paint43_linear_129_12217" x1="251.463" y1="186.24" x2="270.436" y2="227.113" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#F02E65" stop-opacity="0.16"/>
</linearGradient>
<linearGradient id="paint44_linear_129_12217" x1="267.519" y1="186.008" x2="308.759" y2="186.008" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#F02E65" stop-opacity="0.49"/>
</linearGradient>
<linearGradient id="paint45_linear_129_12217" x1="366.349" y1="17.2409" x2="306.751" y2="66.01" gradientUnits="userSpaceOnUse">
<stop stop-color="#AC2D5A"/>
<stop offset="1" stop-color="#97325D"/>
</linearGradient>
<linearGradient id="paint46_linear_129_12217" x1="259.68" y1="30.1474" x2="281.317" y2="78.3572" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#7C335B"/>
</linearGradient>
<linearGradient id="paint47_linear_129_12217" x1="279.037" y1="30.1473" x2="328.765" y2="30.1473" gradientUnits="userSpaceOnUse">
<stop stop-color="#DD2E62"/>
<stop offset="1" stop-color="#B62D5C"/>
</linearGradient>
<linearGradient id="paint48_linear_129_12217" x1="370.446" y1="67.7021" x2="347.064" y2="86.8359" gradientUnits="userSpaceOnUse">
<stop stop-color="#A12D59"/>
<stop offset="1" stop-color="#A1315E"/>
</linearGradient>
<linearGradient id="paint49_linear_129_12217" x1="328.596" y1="72.7658" x2="337.085" y2="91.6801" gradientUnits="userSpaceOnUse">
<stop stop-color="#B32E5C"/>
<stop offset="1" stop-color="#79335A"/>
</linearGradient>
<linearGradient id="paint50_linear_129_12217" x1="336.192" y1="72.7659" x2="355.702" y2="72.7659" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#BE2D5D"/>
</linearGradient>
<linearGradient id="paint51_linear_129_12217" x1="419.411" y1="28.5434" x2="409.454" y2="36.6913" gradientUnits="userSpaceOnUse">
<stop stop-color="#A3315E"/>
<stop offset="1" stop-color="#96325D"/>
</linearGradient>
<linearGradient id="paint52_linear_129_12217" x1="401.589" y1="30.6997" x2="405.204" y2="38.7541" gradientUnits="userSpaceOnUse">
<stop stop-color="#9D2D58"/>
<stop offset="1" stop-color="#6F3359"/>
</linearGradient>
<linearGradient id="paint53_linear_129_12217" x1="404.824" y1="30.6997" x2="413.132" y2="30.6997" gradientUnits="userSpaceOnUse">
<stop stop-color="#C42E5E"/>
<stop offset="1" stop-color="#AF2D5B"/>
</linearGradient>
<clipPath id="clip0_129_12217">
<rect width="600" height="400" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 23 KiB

+253
View File
@@ -0,0 +1,253 @@
<svg width="598" height="382" viewBox="0 0 598 382" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 157.8L151.237 246L311 155.55L160.661 57.0001L0 157.8Z" fill="url(#paint0_linear_129_11322)"/>
<path d="M207 221.153L357.8 305L420 274.673L270.095 177L207 221.153Z" fill="url(#paint1_linear_129_11322)"/>
<path d="M150.677 245.975V121.27C150.677 116.618 153.163 112.32 157.196 110.001L306.264 24.2769C307.597 23.5101 309.261 24.4726 309.261 26.0107V154.565L397.247 207.394C399.799 208.927 399.843 212.611 397.328 214.203L255.191 304.199C253.931 304.996 252.331 305.027 251.042 304.278L150.677 245.975Z" fill="url(#paint2_linear_129_11322)"/>
<path d="M252.352 296.964L155.343 241.722L308.941 154.594L396.07 205.793L387.986 211.632L358.793 230.944L252.352 296.964Z" fill="#FCFCFF"/>
<path d="M235.904 277.736L185.883 247.32L316.576 171.66L360.296 197.892C362.877 199.441 362.887 203.179 360.313 204.741L240.058 277.738C238.782 278.513 237.18 278.512 235.904 277.736Z" fill="white"/>
<path d="M155.343 242.171V122.619C155.343 118.644 157.487 114.979 160.951 113.031L306.859 30.9665C308.192 30.2166 309.839 31.1801 309.839 32.7097V154.145L155.343 242.171Z" fill="url(#paint3_linear_129_11322)"/>
<path d="M160.456 231.842V121.821C160.456 120.38 161.23 119.051 162.484 118.341L297.772 41.677C299.105 40.9215 300.758 41.8846 300.758 43.417V150.552L160.456 231.842Z" fill="url(#paint4_linear_129_11322)"/>
<path d="M171.511 199.329V133.399C171.511 131.238 172.673 129.245 174.552 128.179L282.6 66.9129C283.934 66.1569 285.587 67.12 285.587 68.6527V138.357C285.587 139.788 284.822 141.111 283.58 141.824L177.505 202.797C174.838 204.33 171.511 202.405 171.511 199.329Z" fill="url(#paint5_linear_129_11322)"/>
<mask id="mask0_129_11322" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="171" y="163" width="211" height="125">
<path d="M253.622 286.693L171.508 238.894L301.682 163.706L379.872 210.034C382.511 211.598 382.48 215.428 379.816 216.949L257.618 286.71C256.378 287.417 254.856 287.411 253.622 286.693Z" fill="#F9F9F9"/>
</mask>
<g mask="url(#mask0_129_11322)">
<path d="M181.711 261.493L340.083 169.658" stroke="url(#paint6_radial_129_11322)"/>
<path d="M190.642 268.721L349.013 176.886" stroke="url(#paint7_radial_129_11322)"/>
<path d="M199.567 273.822L357.939 181.988" stroke="url(#paint8_radial_129_11322)"/>
<path d="M208.073 280.625L366.445 188.791" stroke="url(#paint9_radial_129_11322)"/>
<path d="M201.27 239.81L252.076 267.02" stroke="url(#paint10_radial_129_11322)"/>
<path d="M216.574 232.157L266.743 259.154" stroke="url(#paint11_radial_129_11322)"/>
<path d="M294.805 186.24L345.611 213.45" stroke="url(#paint12_radial_129_11322)"/>
<path d="M310.11 178.587L360.279 205.584" stroke="url(#paint13_radial_129_11322)"/>
<path d="M230.181 223.229L270.146 244.699" stroke="url(#paint14_radial_129_11322)"/>
<path d="M242.511 216.001L282.476 237.471" stroke="url(#paint15_radial_129_11322)"/>
<path d="M254.84 208.773L294.805 230.244" stroke="url(#paint16_radial_129_11322)"/>
<path d="M266.746 201.545L306.711 223.016" stroke="url(#paint17_radial_129_11322)"/>
<path d="M280.773 194.318L320.738 215.788" stroke="url(#paint18_radial_129_11322)"/>
</g>
<path d="M462 159V221.398C462 224.296 460.433 226.967 457.904 228.381L362 282" stroke="url(#paint19_radial_129_11322)" stroke-opacity="0.6"/>
<path d="M186 250.414V247.276L238.141 276.414L364 202V205.586L238.141 280L186 250.414Z" fill="url(#paint20_linear_129_11322)"/>
<path d="M356.547 199.657C356.547 196.769 358.103 194.105 360.619 192.688L414.681 162.215C420.014 159.209 426.609 163.063 426.609 169.184V267.568C426.609 270.425 425.086 273.065 422.613 274.495L368.55 305.744C363.217 308.827 356.547 304.978 356.547 298.818V199.657Z" fill="url(#paint21_linear_129_11322)"/>
<path d="M361.936 202.379C361.936 200.935 362.715 199.603 363.974 198.894L414.359 170.526C417.025 169.025 420.321 170.951 420.321 174.011V264.986C420.321 266.415 419.559 267.735 418.321 268.45L367.936 297.541C365.269 299.081 361.936 297.157 361.936 294.077V202.379Z" fill="url(#paint22_linear_129_11322)"/>
<path d="M370.021 234.596V205.632C370.021 204.904 370.416 204.233 371.054 203.881L411.652 181.462C412.319 181.094 413.136 181.576 413.136 182.337V210.144C413.136 210.857 412.756 211.515 412.14 211.873L371.523 235.461C370.856 235.848 370.021 235.367 370.021 234.596Z" fill="url(#paint23_linear_129_11322)"/>
<path d="M370.021 249.806V244.872L413.136 220.165V224.769L370.021 249.806Z" fill="url(#paint24_linear_129_11322)"/>
<path d="M370.021 257.918V255.322C370.021 254.969 370.207 254.642 370.511 254.462L402.644 235.431C403.31 235.036 404.153 235.516 404.153 236.291V238.575C404.153 238.926 403.97 239.251 403.669 239.432L371.536 258.775C370.87 259.176 370.021 258.696 370.021 257.918Z" fill="url(#paint25_linear_129_11322)"/>
<path d="M435 91L349 48" stroke="url(#paint26_radial_129_11322)" stroke-opacity="0.6"/>
<path d="M435.594 61.432C435.594 58.4417 438.755 56.5087 441.417 57.8717L475.634 75.3931C476.97 76.0774 477.811 77.4522 477.811 78.9535V173.165C477.811 176.164 474.632 178.097 471.97 176.717L437.753 158.979C436.426 158.292 435.594 156.922 435.594 155.428V61.432Z" fill="url(#paint27_linear_129_11322)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M445.135 64.8297L436.49 60.2792V149.213C436.49 150.665 437.277 152.003 438.545 152.709L468.271 169.25C470.937 170.734 474.216 168.806 474.216 165.755V82.5532C474.216 81.0682 473.393 79.7054 472.079 79.0137L466.413 76.031L466.487 77.5599C466.524 78.3307 465.711 78.8513 465.027 78.4954L445.809 68.5041C445.493 68.3399 445.289 68.0204 445.271 67.665L445.135 64.8297Z" fill="url(#paint28_linear_129_11322)"/>
<path d="M469.727 119.68V90.7135C469.727 89.9561 469.299 89.2636 468.621 88.9248L441.532 75.3749C440.867 75.0423 440.085 75.5258 440.085 76.2693V104.112C440.085 104.846 440.487 105.521 441.132 105.871L468.25 120.559C468.917 120.92 469.727 120.438 469.727 119.68Z" fill="url(#paint29_linear_129_11322)"/>
<path d="M469.727 134.833V129.898L440.085 113.275V117.879L469.727 134.833Z" fill="url(#paint30_linear_129_11322)"/>
<path d="M358 262.247L307.192 293.501C301.861 296.779 295 292.945 295 286.687V82.0001" stroke="url(#paint31_radial_129_11322)" stroke-opacity="0.6"/>
<path d="M179.149 190.523C180.927 186.993 179.149 177.948 184.1 170.971C185.137 169.51 190.094 179.119 189.928 175.702C189.763 172.286 193.521 162.229 196.665 160.432C198.071 159.629 198.461 164.025 198.911 164.025C198.911 164.025 200.732 146.06 204.749 146.06C205.198 146.06 205.198 151.001 205.647 151.001C206.096 151.001 208.342 141.569 211.486 141.569C211.935 141.569 215.324 149.214 216.875 150.102C219.347 143.922 222.828 150.31 223.848 150.974L224.061 151.001C230.349 145.083 234.391 156.839 234.391 156.839L179.149 190.523Z" fill="#D2EFF7"/>
<mask id="mask1_129_11322" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="201" y="36" width="115" height="138">
<path d="M201.152 169.238V103.308C201.152 101.148 202.314 99.1541 204.193 98.0886L312.241 36.8221C313.575 36.0661 315.228 37.0292 315.228 38.5619V108.266C315.228 109.698 314.463 111.02 313.221 111.734L207.146 172.706C204.479 174.239 201.152 172.314 201.152 169.238Z" fill="white"/>
</mask>
<g mask="url(#mask1_129_11322)">
<path d="M245.166 112.377L248.759 110.58V151.001L245.166 153.695V112.377Z" fill="#D2EFF7"/>
<path d="M250.555 125.85L254.148 124.054V147.408L250.555 150.103V125.85Z" fill="#D2EFF7"/>
<path d="M261.334 118.664L264.927 116.868V140.222L261.334 142.917V118.664Z" fill="#D2EFF7"/>
<path d="M266.723 115.071L270.316 113.275V136.629L266.723 139.324V115.071Z" fill="#D2EFF7"/>
<path d="M272.113 123.248L275.706 122.257V135.142L272.113 136.629V123.248Z" fill="#D2EFF7"/>
<path d="M255.944 113.275L259.537 111.479V143.815L255.944 146.51V113.275Z" fill="#D2EFF7"/>
</g>
<path d="M180 135.566L213 117V122.434L180 141V135.566Z" fill="url(#paint32_linear_129_11322)"/>
<path d="M10 80.0001L119.757 147.082C124.913 150.233 124.848 157.744 119.637 160.805L59.8377 195.938C54.5747 199.03 54.5741 206.64 59.8365 209.733L304.839 353.727C307.292 355.17 310.328 355.2 312.809 353.806L436.612 284.282C439.11 282.879 442.168 282.919 444.629 284.387L635 398" stroke="url(#paint33_radial_129_11322)"/>
<path d="M294.501 23.9936L315 11.8677V35.7664L294.501 48.01V23.9936Z" fill="url(#paint34_linear_129_11322)"/>
<path d="M294.501 23.9936L274.003 11.8677V35.7664L294.501 48.01V23.9936Z" fill="url(#paint35_linear_129_11322)"/>
<path d="M274 11.9017L294.322 0L314.997 11.9017L294.322 24.2747L274 11.9017Z" fill="url(#paint36_linear_129_11322)"/>
<path d="M341.042 59.4135L349.085 54.6561V64.0323L341.042 68.8359V59.4135Z" fill="url(#paint37_linear_129_11322)"/>
<path d="M341.042 59.4135L333 54.6561V64.0323L341.042 68.8359V59.4135Z" fill="url(#paint38_linear_129_11322)"/>
<path d="M333 54.6695L340.974 50L349.085 54.6695L340.974 59.5238L333 54.6695Z" fill="url(#paint39_linear_129_11322)"/>
<path d="M405.741 14.6788L409.166 12.6529V16.6457L405.741 18.6913V14.6788Z" fill="url(#paint40_linear_129_11322)"/>
<path d="M405.741 14.6788L402.316 12.6529V16.6457L405.741 18.6913V14.6788Z" fill="url(#paint41_linear_129_11322)"/>
<path d="M402.316 12.6586L405.712 10.6702L409.166 12.6586L405.712 14.7258L402.316 12.6586Z" fill="url(#paint42_linear_129_11322)"/>
<path d="M294.442 177.447L311.989 167.067V187.524L294.442 198.005V177.447Z" fill="url(#paint43_linear_129_11322)"/>
<path d="M294.442 177.447L276.895 167.067V187.524L294.442 198.005V177.447Z" fill="url(#paint44_linear_129_11322)"/>
<path d="M276.895 167.096L294.291 156.908L311.988 167.096L294.291 177.687L276.895 167.096Z" fill="url(#paint45_linear_129_11322)"/>
<defs>
<linearGradient id="paint0_linear_129_11322" x1="225.733" y1="253.2" x2="123.169" y2="163.028" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint1_linear_129_11322" x1="432.082" y1="312.136" x2="343.25" y2="244.506" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint2_linear_129_11322" x1="-1458.33" y1="-430.156" x2="719.884" y2="345.468" gradientUnits="userSpaceOnUse">
<stop stop-color="#A3A8BD"/>
<stop offset="1" stop-color="#FCFCFF"/>
</linearGradient>
<linearGradient id="paint3_linear_129_11322" x1="-1454.58" y1="-433.23" x2="718.1" y2="364.537" gradientUnits="userSpaceOnUse">
<stop stop-color="#E8E9F0"/>
<stop offset="1" stop-color="#FCFCFF"/>
</linearGradient>
<linearGradient id="paint4_linear_129_11322" x1="-604.56" y1="227.351" x2="369.421" y2="145.85" gradientUnits="userSpaceOnUse">
<stop stop-color="#A3A8BD"/>
<stop offset="1" stop-color="#FCFCFF"/>
</linearGradient>
<linearGradient id="paint5_linear_129_11322" x1="168.817" y1="191.421" x2="392.477" y2="82.735" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<radialGradient id="paint6_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(260.897 215.576) rotate(90) scale(45.9172 79.1859)">
<stop stop-color="#E8E9F0"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint7_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(269.828 222.803) rotate(90) scale(45.9172 79.1859)">
<stop stop-color="#E8E9F0"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint8_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(278.753 227.905) rotate(90) scale(45.9172 79.1859)">
<stop stop-color="#E8E9F0"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint9_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(287.259 234.708) rotate(90) scale(45.9172 79.1859)">
<stop stop-color="#E8E9F0"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint10_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(226.673 253.415) rotate(90) scale(13.6051 25.4033)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint11_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(241.659 245.656) rotate(90) scale(13.4988 25.0844)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint12_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(320.208 199.845) rotate(90) scale(13.6051 25.4033)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint13_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(335.194 192.086) rotate(90) scale(13.4988 25.0844)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint14_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(250.164 233.964) rotate(90) scale(10.7353 19.9825)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint15_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(262.493 226.736) rotate(90) scale(10.7353 19.9825)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint16_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(274.823 219.508) rotate(90) scale(10.7353 19.9825)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint17_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(286.728 212.281) rotate(90) scale(10.7353 19.9825)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint18_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(300.756 205.053) rotate(90) scale(10.7353 19.9825)">
<stop stop-color="#F7F7F7"/>
<stop offset="1" stop-color="#F7F7F7" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint19_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(470.108 220.276) rotate(145.278) scale(52.6119 42.3677)">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#F02E65" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint20_linear_129_11322" x1="221.061" y1="320.345" x2="326.012" y2="233.996" gradientUnits="userSpaceOnUse">
<stop stop-color="#E8E9F0"/>
<stop offset="1" stop-color="#FCFCFF"/>
</linearGradient>
<linearGradient id="paint21_linear_129_11322" x1="376.757" y1="-252.755" x2="394.722" y2="318.521" gradientUnits="userSpaceOnUse">
<stop stop-color="#F3F3F3"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<linearGradient id="paint22_linear_129_11322" x1="411.339" y1="102.496" x2="413.569" y2="465.382" gradientUnits="userSpaceOnUse">
<stop stop-color="#E8E9F0"/>
<stop offset="1" stop-color="#FCFCFF"/>
</linearGradient>
<linearGradient id="paint23_linear_129_11322" x1="354.751" y1="228.249" x2="444.124" y2="227.985" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint24_linear_129_11322" x1="370.021" y1="220.165" x2="435.698" y2="247.569" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint25_linear_129_11322" x1="362.386" y1="259.687" x2="435.611" y2="257.427" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<radialGradient id="paint26_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(397.178 66.3646) rotate(90) scale(24.6354 49.2708)">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#F02E65" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint27_linear_129_11322" x1="505.656" y1="-530.309" x2="458.05" y2="231.393" gradientUnits="userSpaceOnUse">
<stop stop-color="#E8E9F0"/>
<stop offset="1" stop-color="#FCFCFF"/>
</linearGradient>
<linearGradient id="paint28_linear_129_11322" x1="455.353" y1="32.9542" x2="462.949" y2="252.004" gradientUnits="userSpaceOnUse">
<stop stop-color="#E8E9F0"/>
<stop offset="1" stop-color="#FCFCFF"/>
</linearGradient>
<linearGradient id="paint29_linear_129_11322" x1="484.997" y1="113.275" x2="395.623" y2="113.011" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint30_linear_129_11322" x1="469.727" y1="105.191" x2="404.049" y2="132.595" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<radialGradient id="paint31_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(239.149 259.543) rotate(-41.9691) scale(249.995 96.3993)">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#F02E65" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint32_linear_129_11322" x1="86.5" y1="146.434" x2="217.578" y2="140.867" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<radialGradient id="paint33_radial_129_11322" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(200.068 292.713) rotate(28.9342) scale(309.625 608.349)">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="#F02E65" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint34_linear_129_11322" x1="364.349" y1="-0.759149" x2="304.751" y2="48.01" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<linearGradient id="paint35_linear_129_11322" x1="257.68" y1="12.1474" x2="279.317" y2="60.3572" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<linearGradient id="paint36_linear_129_11322" x1="277.037" y1="12.1473" x2="326.765" y2="12.1473" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<linearGradient id="paint37_linear_129_11322" x1="368.446" y1="49.7021" x2="345.064" y2="68.8359" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<linearGradient id="paint38_linear_129_11322" x1="326.596" y1="54.7658" x2="335.085" y2="73.6801" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<linearGradient id="paint39_linear_129_11322" x1="334.192" y1="54.7659" x2="353.702" y2="54.7659" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<linearGradient id="paint40_linear_129_11322" x1="417.411" y1="10.5434" x2="407.454" y2="18.6913" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<linearGradient id="paint41_linear_129_11322" x1="399.589" y1="12.6997" x2="403.204" y2="20.7541" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<linearGradient id="paint42_linear_129_11322" x1="402.824" y1="12.6997" x2="411.132" y2="12.6997" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<linearGradient id="paint43_linear_129_11322" x1="354.231" y1="156.258" x2="303.215" y2="198.005" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<linearGradient id="paint44_linear_129_11322" x1="262.922" y1="167.306" x2="281.444" y2="208.574" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<linearGradient id="paint45_linear_129_11322" x1="279.494" y1="167.306" x2="322.062" y2="167.306" gradientUnits="userSpaceOnUse">
<stop stop-color="#F02E65"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 20 KiB

+40 -7
View File
@@ -1,20 +1,30 @@
<script lang="ts">
import { base } from '$app/paths';
import { onMount } from 'svelte';
import { Breadcrumbs } from '.';
import { Avatar, DropList, DropListItem, DropListLink } from '$lib/components';
import { app } from '$lib/stores/app';
import { sdkForConsole } from '$lib/stores/sdk';
import { user } from '$lib/stores/user';
import { project } from '../../routes/console/[project]/store';
import AppwriteLogo from '$lib/images/appwrite-gray-light.svg';
import LightMode from '$lib/images/mode/light-mode.svg';
import DarkMode from '$lib/images/mode/dark-mode.svg';
import SystemMode from '$lib/images/mode/system-mode.svg';
import { organizationList, organization, newOrgModal } from '$lib/stores/organization';
let showDropdown = false;
onMount(async () => {
await organizationList.load();
if (!$organization) {
await organization.load($organizationList.teams[0].$id);
}
});
</script>
<a class="logo" href={`${base}/console`}>
<a
class="logo"
href={$organization ? `${base}/console/organization-${$organization.$id}` : `${base}/console`}>
<img src={AppwriteLogo} width="132" height="34" alt="Appwrite" />
</a>
@@ -33,7 +43,12 @@
</nav>
<nav class="user-profile">
{#if $user}
<DropList bind:show={showDropdown} position="bottom" horizontal="left" arrow={false}>
<DropList
bind:show={showDropdown}
position="bottom"
horizontal="left"
arrow={false}
scrollable={true}>
<button class="user-profile-button" on:click={() => (showDropdown = !showDropdown)}>
<Avatar
size={40}
@@ -41,8 +56,8 @@
src={sdkForConsole.avatars.getInitials($user.name, 40, 40).toString()} />
<span class="user-profile-info is-only-desktop">
<span class="name">{$user.name}</span>
{#if $project}
<span class="title">{$project.name}</span>
{#if $organization}
<span class="title">{$organization.name}</span>
{/if}
</span>
<span
@@ -52,10 +67,28 @@
class:icon-cheveron-down={!showDropdown} />
</button>
<svelte:fragment slot="list">
<DropListItem icon="plus">New organisation</DropListItem>
<DropListLink href="/console/$me">Your Account</DropListLink>
{#if $organizationList?.total}
{#each $organizationList.teams as org}
<DropListLink
href={`${base}/console/organization-${org.$id}`}
on:click={() => {
showDropdown = false;
}}>{org.name}</DropListLink>
{/each}
{/if}
</svelte:fragment>
<svelte:fragment slot="other">
<section class="drop-section">
<ul class="drop-list">
<DropListItem
icon="plus"
on:click={() => {
showDropdown = false;
newOrgModal.set(true);
}}>New organization</DropListItem>
<DropListLink href="/console/$me">Your Account</DropListLink>
</ul>
</section>
<section class="drop-section">
<ul class="u-flex u-gap-12">
<li>
+1
View File
@@ -8,3 +8,4 @@ export { default as Notifications } from './notifications.svelte';
export { default as Shell } from './shell.svelte';
export { default as Wizard } from './wizard.svelte';
export { default as Breadcrumbs } from './breadcrumbs.svelte';
export { default as Unauthenticated } from './unauthenticated.svelte';
+1 -1
View File
@@ -3,7 +3,7 @@
import { page } from '$app/stores';
$: project = $page.params.project;
$: path = `${base}/console/${project}`;
$: path = `${base}/console/project-${project}`;
</script>
<div class="side-nav">
+87 -15
View File
@@ -1,18 +1,26 @@
<script lang="ts">
import { navigating, page } from '$app/stores';
import { tabs, title, backButton, copyData } from '$lib/stores/layout';
import { tabs, title, backButton, copyData, titleDropdown } from '$lib/stores/layout';
import { Cover } from '.';
import { Copy } from '$lib/components';
import { Copy, DropList, DropListItem, DropListLink, AvatarGroup } from '$lib/components';
import { Pill } from '$lib/elements';
import { Button } from '$lib/elements/forms';
import {
organization,
memberList,
newOrgModal,
newMemberModal
} from '$lib/stores/organization';
import { sdkForConsole } from '$lib/stores/sdk';
import { base } from '$app/paths';
export let isOpen = false;
export let showSideNavigation = false;
$: base = `/console/${$page.params.project}`;
let tabsList: HTMLUListElement;
let showLeft = false;
let showRight = false;
let showDropdown = false;
navigating.subscribe(() => {
if (isOpen) isOpen = false;
@@ -32,6 +40,20 @@
}
}, 10);
};
let avatars = [];
let avatarsTotal = 0;
memberList.subscribe((value) => {
if (value?.total > 0) {
avatarsTotal = value.total;
avatars = value.memberships.map((team) => {
return {
name: team.userName,
img: sdkForConsole.avatars.getInitials(team.userName, 80, 80).toString()
};
});
}
});
const onScroll = () => {
if (!tabsList) {
@@ -78,14 +100,65 @@
<section class="main-content">
<Cover>
<svelte:fragment slot="header">
<h1 class="heading-level-4">
{#if $backButton}
<a class="back-button" href={$backButton} aria-label="page back">
<span class="icon-cheveron-left" aria-hidden="true" />
</a>
{/if}
<span class="text"> {$title}</span>
</h1>
{#if $backButton}
<a class="back-button" href={$backButton} aria-label="page back">
<span class="icon-cheveron-left" aria-hidden="true" />
</a>
{/if}
{#if $titleDropdown?.length && $organization}
<DropList
bind:show={showDropdown}
position="bottom"
arrow={false}
scrollable={true}>
<button
class="button is-text u-padding-inline-0"
on:click={() => (showDropdown = !showDropdown)}>
<h1 class="heading-level-4">
<span class="text"> {$organization.name}</span>
<span
class={`icon-cheveron-${showDropdown ? 'up' : 'down'}`}
aria-hidden="true" />
</h1>
</button>
<svelte:fragment slot="list">
{#each $titleDropdown as org}
<DropListLink
href={`${base}/console/organization-${org.$id}`}
on:click={() => {
showDropdown = false;
}}>
{org.name}
</DropListLink>
{/each}
</svelte:fragment>
<svelte:fragment slot="other">
<section class="drop-section">
<ul class="drop-list">
<DropListItem
icon="plus"
on:click={() => {
showDropdown = false;
newOrgModal.set(true);
}}>New Organization</DropListItem>
</ul>
</section></svelte:fragment>
</DropList>
<div class="u-margin-inline-start-auto">
<div class="u-flex u-gap-16">
<AvatarGroup size={40} {avatars} total={avatarsTotal} />
<Button secondary on:click={() => newMemberModal.set(true)}>
<span class="icon-plus" aria-hidden="true" />
<span class="text">Invite</span>
</Button>
</div>
</div>
{:else}
<h1 class="heading-level-4">
<span class="text"> {$title}</span>
</h1>
{/if}
{#if $copyData?.value}
<Copy value={$copyData.value}>
<Pill button>
@@ -122,9 +195,8 @@
<li class="tabs-item">
<a
class="tabs-button"
href={`${base}/${tab.href}`}
class:is-selected={$page.url.pathname ===
`${base}/${tab.href}`}>
href={tab.href}
class:is-selected={$page.url.pathname === tab.href}>
<span class="text">{tab.title}</span>
</a>
</li>
+86
View File
@@ -0,0 +1,86 @@
<script lang="ts">
import AppwriteLogo from '$lib/images/appwrite.svg';
import LoginLight from '$lib/images/login/login-light-mode.svg';
import LoginDark from '$lib/images/login/login-dark-mode.svg';
import { app } from '$lib/stores/app';
const technologies = [
'js',
'flutter',
'apple',
'android',
'node_js',
'php',
'python',
'ruby',
'dart',
'kotlin',
'swift'
];
</script>
<main class="grid-1-1 is-full-page" id="main">
<section class="grid-1-1-col-1 u-flex u-flex-vertical">
<div
class="container u-margin-block-start-20"
style="--p-container-max-size: var(--container-size-medium);">
<a href="/">
<img src={AppwriteLogo} width="196" height="47" class="u-block" alt="Appwrite" />
</a>
</div>
<div class="u-margin-block-start-auto" />
<div
class="container u-margin-block-start-20"
style="--p-container-max-size: var(--container-size-large);">
{#if $app.themeInUse === 'dark'}
<img src={LoginDark} alt="" class="u-only-dark" />
{:else}
<img src={LoginLight} alt="" class="u-only-light" />
{/if}
</div>
<div class="u-margin-block-start-auto" />
<div
class="container u-text-color-light-gray is-only-desktop"
style="--p-container-max-size:var(--container-size-small); --p-container-padding-inline:1rem;">
<p>Integrate with your favourite technologies</p>
<ul
class="u-flex u-main-center u-flex-wrap u-gap-16 u-margin-block-start-32 u-line-height-1 ">
{#each technologies as tech}
<li>
<span
class={`icon-${tech} u-font-size-32`}
aria-hidden="true"
aria-label={tech} />
</li>
{/each}
</ul>
</div>
<div class="u-margin-block-start-40" />
</section>
<section class="grid-1-1-col-2 u-flex u-main-center u-cross-center">
<div class="container u-flex u-flex-vertical u-cross-center">
<div class="u-margin-block-start-auto" />
<div class="u-max-width-500 u-width-full-line">
<h1 class="heading-level-3 u-margin-block-start-auto"><slot name="title" /></h1>
<div class="u-margin-block-start-40">
<slot />
</div>
<ul class="inline-links is-center is-with-sep u-margin-block-start-32">
<slot name="links" />
</ul>
</div>
<div class="u-margin-block-start-auto" />
<p class="u-max-width-500 u-width-full-line u-margin-block-start-24">
version 0.15.2.402
</p>
<div class="u-margin-block-start-20" />
</div>
</section>
</main>
+14 -3
View File
@@ -1,5 +1,6 @@
import { project } from '../../routes/console/[project]/store';
import { get, readable, writable } from 'svelte/store';
import { project } from '../../routes/console/project-[project]/store';
import { get, writable, readable } from 'svelte/store';
import type { Models } from '@aw-labs/appwrite-console';
export type Tab = {
href: string;
@@ -14,6 +15,7 @@ export type Breadcrumb = {
export type updateLayoutArguments = {
title: string;
titleDropdown?: Models.Team[];
level?: number;
tabs?: Tab[];
back?: string;
@@ -22,6 +24,7 @@ export type updateLayoutArguments = {
text: string;
value: string;
};
customBase?: string;
navigate?: {
from: URL | null;
to: URL;
@@ -30,6 +33,7 @@ export type updateLayoutArguments = {
export const level = writable<number>();
export const title = writable<string>('');
export const titleDropdown = writable<Models.Team[]>([]);
export const backButton = writable<string>('');
export const tabs = writable<Tab[]>([]);
export const breadcrumbs = writable<Map<number, Breadcrumb>>(new Map());
@@ -40,7 +44,13 @@ export const copyData = writable({
export function updateLayout(args: updateLayoutArguments) {
const projectId = get(project)?.$id;
const base = projectId ? `/console/${projectId}` : `/console`;
const base = args?.customBase ?? projectId ? `/console/project-${projectId}` : ``;
if (args?.tabs) {
args.tabs.map((tab) => {
tab.href = `${base}/${tab.href}`;
});
}
if (args?.navigate?.to) {
const previousTabs = get(tabs);
@@ -50,6 +60,7 @@ export function updateLayout(args: updateLayoutArguments) {
}
title.set(args.title);
titleDropdown.set(args.titleDropdown ?? []);
backButton.set(args.back ?? null);
copyData.set(args.copy ?? null);
level.set(args.level ?? null);
+5 -5
View File
@@ -1,11 +1,11 @@
import { writable } from 'svelte/store';
import type { Models } from '@aw-labs/appwrite-console';
import type { SvelteComponent } from 'svelte';
import Apple from '../../routes/console/[project]/authentication/_appleOAuth.svelte';
import Microsoft from '../../routes/console/[project]/authentication/_microsoftOAuth.svelte';
import Okta from '../../routes/console/[project]/authentication/_oktaOAuth.svelte';
import Auth0 from '../../routes/console/[project]/authentication/_auth0OAuth.svelte';
import Main from '../../routes/console/[project]/authentication/_mainOAuth.svelte';
import Apple from '../../routes/console/project-[project]/authentication/_appleOAuth.svelte';
import Microsoft from '../../routes/console/project-[project]/authentication/_microsoftOAuth.svelte';
import Okta from '../../routes/console/project-[project]/authentication/_oktaOAuth.svelte';
import Auth0 from '../../routes/console/project-[project]/authentication/_auth0OAuth.svelte';
import Main from '../../routes/console/project-[project]/authentication/_mainOAuth.svelte';
export type Provider = {
name: string;
+115
View File
@@ -0,0 +1,115 @@
import { sdkForConsole } from '$lib/stores/sdk';
import type { Models } from '@aw-labs/appwrite-console';
import { writable } from 'svelte/store';
import { browser } from '$app/env';
import { get } from 'svelte/store';
import { base } from '$app/paths';
import { goto } from '$app/navigation';
function createOrganizationList() {
const { subscribe, set } = writable<Models.TeamList>(
browser ? JSON.parse(sessionStorage.getItem('organizationList')) : null
);
return {
subscribe,
set,
load: async () => {
const response = await sdkForConsole.teams.list();
set(response);
}
};
}
function createOrganization() {
const { subscribe, set } = writable<Models.Team>(
browser ? JSON.parse(sessionStorage.getItem('organization')) : null
);
return {
subscribe,
set,
load: async (teamId: string) => {
const response = await sdkForConsole.teams.get(teamId);
set(response);
},
deleteCache: () => {
sessionStorage.removeItem('organization');
}
};
}
function createProjectList() {
const { subscribe, set } = writable<Models.ProjectList>(
browser ? JSON.parse(sessionStorage.getItem('projectList')) : null
);
return {
subscribe,
set,
load: async (search: string, limit: number, offset: number) => {
const response = await sdkForConsole.projects.list(
search,
limit,
offset,
undefined,
undefined,
'ASC'
);
set(response);
}
};
}
function createMemberList() {
const { subscribe, set } = writable<Models.MembershipList>(
browser ? JSON.parse(sessionStorage.getItem('memberList')) : null
);
return {
subscribe,
set,
load: async (teamId: string, search: string, limit: number, offset: number) => {
const response = await sdkForConsole.teams.getMemberships(
teamId,
search,
limit,
offset
);
set(response);
}
};
}
export const organizationList = createOrganizationList();
export const organization = createOrganization();
export const projectList = createProjectList();
export const memberList = createMemberList();
export const newOrgModal = writable<boolean>(false);
export const newMemberModal = writable<boolean>(false);
if (browser) {
organizationList.subscribe((n) =>
sessionStorage?.setItem('organizationList', JSON.stringify(n ?? ''))
);
organization.subscribe((n) => sessionStorage?.setItem('organization', JSON.stringify(n ?? '')));
projectList.subscribe((n) => sessionStorage?.setItem('projectList', JSON.stringify(n ?? '')));
memberList.subscribe((n) => sessionStorage?.setItem('memberList', JSON.stringify(n ?? '')));
}
export const redirectTo = async () => {
let org = get(organization);
if (org) {
await goto(`${base}/console/organization-${org.$id}`);
} else {
await organizationList.load();
const orgList = get(organizationList);
if (orgList?.total) {
await organization.load(orgList.teams[0].$id);
org = get(organization);
await goto(`${base}/console/organization-${org.$id}`);
} else {
newOrgModal.set(true);
await goto(`${base}/console`);
}
}
};
+2 -1
View File
@@ -7,6 +7,7 @@
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { user } from '$lib/stores/user';
import { redirectTo } from '$lib/stores/organization';
import { onMount } from 'svelte';
import { base } from '$app/paths';
import { browser } from '$app/env';
@@ -29,7 +30,7 @@
}
if (!$page.url.pathname.startsWith('/console')) {
await goto(`${base}/console`);
await redirectTo();
}
} catch (error) {
await goto(`${base}/login`);
@@ -1,113 +0,0 @@
<script lang="ts">
import { page } from '$app/stores';
import { Empty, Pagination } from '$lib/components';
import {
Table,
TableBody,
TableHeader,
TableRow,
TableCellHead,
TableCellText
} from '$lib/elements/table';
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import { sdkForProject } from '$lib/stores/sdk';
import DeleteAllSessions from './_deleteAllSessions.svelte';
import DeleteSessions from './_deleteSession.svelte';
import { toLocaleDateTime } from '$lib/helpers/date';
import { app } from '$lib/stores/app';
import { pageLimit } from '$lib/stores/layout';
let offset = 0;
let showDelete = false;
let showDeleteAll = false;
let selectedSessionId: string = null;
const request = sdkForProject.users.getSessions($page.params.user);
//TODO: replace session.expire with "last activity"
</script>
<Container>
{#await request}
<div aria-busy="true" />
{:then response}
{#if response.total}
<div class="u-flex u-main-end common-section">
<Button secondary on:click={() => (showDeleteAll = true)}>
<span class="icon-plus" aria-hidden="true" />
<span class="text">Delete All</span>
</Button>
</div>
<Table>
<TableHeader>
<TableCellHead>Browser</TableCellHead>
<TableCellHead>Device</TableCellHead>
<TableCellHead>IP</TableCellHead>
<TableCellHead width={30} />
</TableHeader>
<TableBody>
{#each response.sessions as session}
<TableRow>
<TableCellText title="Client">
<div class="u-flex u-cross-center u-gap-12">
<div class="image-item">
<img
height="20"
width="20"
src={`/icons/${
$app.themeInUse
}/color/${session?.clientName.toLocaleLowerCase()}.svg`}
alt={session.clientName} />
</div>
<span class="u-line-height-1-5">
<p>{session.clientName}</p>
<span class="u-small">
Last activity: {toLocaleDateTime(session?.expire)}
</span></span>
</div>
</TableCellText>
<TableCellText title="IP">{session.ip}</TableCellText>
<TableCellText title="">
<button
class="button is-only-icon is-text"
aria-label="Delete item"
on:click={() => {
selectedSessionId = session.$id;
showDelete = true;
}}>
<span class="icon-trash" aria-hidden="true" />
</button>
</TableCellText>
</TableRow>
{/each}
</TableBody>
</Table>
{:else}
<Empty centered>
<div class="u-flex u-flex-vertical u-cross-center">
<div class="common-section">
<p>No session available</p>
</div>
<div class="common-section">
<Button
external
secondary
href="https://appwrite.io/docs/server/authentication?sdk=nodejs-default#usersGetSessions"
>Documentation</Button>
</div>
</div>
</Empty>
{/if}
<div
class="u-flex u-margin-block-start-32
u-main-space-between">
<p class="text">Total results: {response.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={response.total} />
</div>
{/await}
</Container>
<DeleteSessions {selectedSessionId} bind:showDelete />
<DeleteAllSessions bind:showDeleteAll />
-18
View File
@@ -1,18 +0,0 @@
<script lang="ts">
import Shell from '$lib/layout/shell.svelte';
import Header from '$lib/layout/header.svelte';
import { updateLayout } from '$lib/stores/layout';
updateLayout({
title: 'Projects',
level: 0
});
</script>
<Shell>
<svelte:fragment slot="header">
<Header />
</svelte:fragment>
<slot />
<footer class="main-footer" />
</Shell>
+30 -2
View File
@@ -3,14 +3,40 @@
import SideNavigation from '$lib/layout/navigation.svelte';
import Header from '$lib/layout/header.svelte';
import { updateLayout } from '$lib/stores/layout';
import {
organization,
organizationList,
newOrgModal,
redirectTo
} from '$lib/stores/organization';
import Create from './_createOrganization.svelte';
import { page } from '$app/stores';
import { afterNavigate } from '$app/navigation';
import { onMount } from 'svelte';
updateLayout({
title: 'Projects',
title: $organization?.name ?? '',
level: 0
});
onMount(async () => {
if ($page.url.pathname === '/console' && !$newOrgModal) {
await redirectTo();
}
});
afterNavigate(async () => {
if ($page.url.pathname === '/console' && !$newOrgModal) {
await redirectTo();
}
});
</script>
<Shell showSideNavigation>
<svelte:head>
<title>Appwrite - Console</title>
</svelte:head>
<Shell showSideNavigation={$page.url.pathname !== '/console' && !$page?.params.organization}>
<svelte:fragment slot="header">
<Header />
</svelte:fragment>
@@ -20,3 +46,5 @@
<slot />
<footer class="main-footer" />
</Shell>
<Create bind:show={$newOrgModal} closable={!!$organizationList?.total} />
+71 -12
View File
@@ -1,37 +1,96 @@
<script lang="ts">
import { Modal } from '$lib/components';
import { InputText, Button, Form } from '$lib/elements/forms';
import { Modal, InnerModal } from '$lib/components';
import { Pill } from '$lib/elements';
import { InputText, Button, Form, FormList } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
import { createEventDispatcher } from 'svelte';
import { organization, organizationList } from '$lib/stores/organization';
import { titleDropdown } from '$lib/stores/layout';
import { goto } from '$app/navigation';
export let show = false;
export let closable = true;
const dispatch = createEventDispatcher();
let name: string;
let id: string;
let showDropdown = false;
let error: string;
const create = async () => {
try {
await sdkForConsole.teams.create('unique()', name);
name = null;
const team = await sdkForConsole.teams.create(id ?? 'unique()', name);
dispatch('created');
} catch (error) {
await organizationList.load();
titleDropdown.set($organizationList.teams);
organization.set(team);
await goto(`/console/organization-${$organization.$id}`);
addNotification({
type: 'error',
message: error.message
type: 'success',
message: `${name} has been created`
});
name = null;
id = null;
show = false;
} catch ({ message }) {
error = message;
}
};
</script>
<Form on:submit={create}>
<Modal bind:show>
<svelte:fragment slot="header">Create Project</svelte:fragment>
<InputText id="name" label="Name" bind:value={name} required />
<Modal {error} size="big" bind:show {closable}>
<svelte:fragment slot="header">Create New Organization</svelte:fragment>
<FormList>
<InputText
id="name"
label="Name"
placeholder="Enter name"
bind:value={name}
autofocus={true}
required />
{#if !showDropdown}
<div>
<Pill button on:click={() => (showDropdown = !showDropdown)}>
<span class="icon-pencil" aria-hidden="true" /><span class="text">
Organization ID
</span>
</Pill>
</div>
{:else}
<InnerModal bind:show={showDropdown}>
<svelte:fragment slot="title">Organization ID</svelte:fragment>
<svelte:fragment slot="subtitle">
Enter a custom organization ID. Leave blank for a randomly generated one.
</svelte:fragment>
<svelte:fragment slot="content">
<div class="form">
<InputText
id="id"
label="Custom ID"
showLabel={false}
placeholder="Enter ID"
autofocus={true}
bind:value={id} />
<div class="u-flex u-gap-4 u-margin-block-start-8 u-small">
<span
class="icon-info u-cross-center u-margin-block-start-2 u-line-height-1 u-icon-small"
aria-hidden="true" />
<span class="text u-line-height-1-5">
Allowed characters: alphanumeric, hyphen, non-leading
underscore, period
</span>
</div>
</div>
</svelte:fragment>
</InnerModal>
{/if}
</FormList>
<svelte:fragment slot="footer">
<Button disabled={!closable} secondary on:click={() => (show = false)}>Cancel</Button>
<Button submit>Create</Button>
<Button secondary on:click={() => (show = false)}>Cancel</Button>
</svelte:fragment>
</Modal>
</Form>
-40
View File
@@ -1,40 +0,0 @@
<script lang="ts">
import { Modal } from '$lib/components';
import { InputText, Button, InputCustomId, Form } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
import { createEventDispatcher } from 'svelte';
export let show = false;
export let teamId: string;
const dispatch = createEventDispatcher();
let id: string;
let name: string;
const create = async () => {
try {
const project = await sdkForConsole.projects.create(id, name, teamId);
id = name = null;
dispatch('created', project);
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
}
};
</script>
<Form on:submit={create}>
<Modal bind:show>
<svelte:fragment slot="header">Create Project</svelte:fragment>
<InputCustomId id="id" label="ID" bind:value={id} required />
<InputText id="name" label="Name" bind:value={name} required />
<svelte:fragment slot="footer">
<Button submit>Create</Button>
<Button secondary on:click={() => (show = false)}>Cancel</Button>
</svelte:fragment>
</Modal>
</Form>
View File
-67
View File
@@ -1,67 +0,0 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { base } from '$app/paths';
import { Tiles, Tile } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import { sdkForConsole } from '$lib/stores/sdk';
import type { Models } from '@aw-labs/appwrite-console';
import CreateOrganization from './_createOrganization.svelte';
import CreateProject from './_createProject.svelte';
type Organization = Models.Team & {
projects: Models.Project[];
};
const request: Promise<Organization[]> = Promise.all([
sdkForConsole.projects.list(),
sdkForConsole.teams.list()
]).then(([{ projects }, { teams }]) => {
return teams.map((team) => {
return {
...team,
projects: projects.filter((a) => a.teamId === team.$id)
};
});
});
let addProject = false;
let addOrganization = false;
let currentOrganization = '';
const createProject = (teamId: string) => {
currentOrganization = teamId;
addProject = true;
};
const projectCreated = async (event: CustomEvent<Models.Project>) => {
await goto(`${base}/console/${event.detail.$id}`);
};
</script>
<svelte:head>
<title>Appwrite - Console</title>
</svelte:head>
<Container>
<h1>Your Organizations</h1>
<Button on:click={() => (addOrganization = true)}>Add Organization</Button>
{#await request}
<div aria-busy="true" />
{:then organizations}
{#each organizations as organization}
<h1>{organization.name}</h1>
<Tiles>
{#each organization.projects as project}
<Tile href={`${base}/console/${project.$id}`} title={project.name} />
{/each}
</Tiles>
<Button on:click={() => createProject(organization.$id)}>Create Project</Button>
{/each}
{/await}
</Container>
<CreateOrganization bind:show={addOrganization} />
<CreateProject
bind:show={addProject}
bind:teamId={currentOrganization}
on:created={projectCreated} />
@@ -0,0 +1,64 @@
<script lang="ts">
import { updateLayout } from '$lib/stores/layout';
import { onMount } from 'svelte';
import { afterNavigate } from '$app/navigation';
import {
organizationList,
organization,
memberList,
newOrgModal,
newMemberModal
} from '$lib/stores/organization';
import CreateMember from './_createMember.svelte';
import Create from '../_createOrganization.svelte';
import { page } from '$app/stores';
$: organizationId = $page.params.organization;
$: path = `console/organization-${organizationId}`;
onMount(handle);
afterNavigate(handle);
async function handle(event = null) {
if ($organization.$id !== organizationId) {
await organization.load(organizationId);
await memberList.load(organizationId, '', 12, 0);
}
updateLayout({
navigate: event,
title: $organization?.name,
titleDropdown: $organizationList.teams,
level: 0,
customBase: '',
breadcrumbs: {
title: `${$organization.name}`,
href: path
},
tabs: [
{
href: path,
title: 'Projects'
},
{
href: `${path}/members`,
title: 'Members'
},
{
href: `${path}/settings`,
title: 'Settings'
}
]
});
}
</script>
<svelte:head>
<title>Appwrite - Organizations</title>
</svelte:head>
{#if $organization}
<slot />
{/if}
<Create bind:show={$newOrgModal} />
<CreateMember bind:showCreate={$newMemberModal} />
@@ -0,0 +1,66 @@
<script lang="ts">
import { page } from '$app/stores';
import { Modal } from '$lib/components';
import { InputText, InputEmail, Button, Form, FormList } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
import { createEventDispatcher } from 'svelte';
import { organization, memberList } from '$lib/stores/organization';
import { pageLimit } from '$lib/stores/layout';
export let showCreate = false;
const dispatch = createEventDispatcher();
let email: string, name: string, error: string;
const url = `${$page.url.origin}/console/`;
const create = async () => {
try {
const team = await sdkForConsole.teams.createMembership(
$organization.$id,
email,
[],
url,
name
);
showCreate = false;
addNotification({
type: 'success',
message: `Invite has been sent to ${email}`
});
memberList.load($organization.$id, '', $pageLimit, 0);
dispatch('created', team);
} catch ({ message }) {
error = message;
}
};
$: if (!showCreate) {
error = null;
}
</script>
<Form on:submit={create}>
<Modal {error} size="big" bind:show={showCreate}>
<svelte:fragment slot="header">Invite Member</svelte:fragment>
<FormList>
<InputEmail
id="email"
label="Email"
placeholder="Enter email"
autofocus={true}
bind:value={email} />
<InputText
id="name"
label="Name (optional)"
placeholder="Enter name"
bind:value={name} />
</FormList>
<svelte:fragment slot="footer">
<Button secondary on:click={() => (showCreate = false)}>Cancel</Button>
<Button submit>Send invite</Button>
</svelte:fragment>
</Modal>
</Form>
@@ -0,0 +1,84 @@
<script lang="ts">
import { Modal, InnerModal } from '$lib/components';
import { Pill } from '$lib/elements';
import { InputText, Button, Form, FormList } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
import { createEventDispatcher } from 'svelte';
export let show = false;
export let teamId: string;
const dispatch = createEventDispatcher();
let id: string;
let name: string;
let showDropdown = false;
let error: string;
const create = async () => {
try {
const project = await sdkForConsole.projects.create(id ?? 'unique()', name, teamId);
dispatch('created', project);
addNotification({
type: 'success',
message: `${name} has been created`
});
id = name = null;
showDropdown = false;
show = false;
} catch ({ message }) {
error = message;
}
};
</script>
<Form on:submit={create}>
<Modal {error} size="big" bind:show>
<svelte:fragment slot="header">Create Project</svelte:fragment>
<FormList>
<InputText id="name" label="Name" bind:value={name} required autofocus={true} />
{#if !showDropdown}
<div>
<Pill button on:click={() => (showDropdown = !showDropdown)}>
<span class="icon-pencil" aria-hidden="true" /><span class="text">
Project ID
</span>
</Pill>
</div>
{:else}
<InnerModal bind:show={showDropdown}>
<svelte:fragment slot="title">Project ID</svelte:fragment>
<svelte:fragment slot="subtitle">
Enter a custom project ID. Leave blank for a randomly generated one.
</svelte:fragment>
<svelte:fragment slot="content">
<div class="form">
<InputText
id="id"
label="Custom ID"
showLabel={false}
placeholder="Enter ID"
autofocus={true}
bind:value={id} />
<div class="u-flex u-gap-4 u-margin-block-start-8 u-small">
<span
class="icon-info u-cross-center u-margin-block-start-2 u-line-height-1 u-icon-small"
aria-hidden="true" />
<span class="text u-line-height-1-5">
Allowed characters: alphanumeric, hyphen, non-leading
underscore, period
</span>
</div>
</div>
</svelte:fragment>
</InnerModal>
{/if}
</FormList>
<svelte:fragment slot="footer">
<Button secondary on:click={() => (show = false)}>Cancel</Button>
<Button submit>Create</Button>
</svelte:fragment>
</Modal>
</Form>
@@ -0,0 +1,50 @@
<script lang="ts">
import { Modal } from '$lib/components';
import { Button, Form } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
import type { Models } from '@aw-labs/appwrite-console';
import { createEventDispatcher } from 'svelte';
import { user } from '$lib/stores/user';
const dispatch = createEventDispatcher();
export let showDelete = false;
export let selectedMember: Models.Membership;
const deleteMembership = async () => {
try {
await sdkForConsole.teams.deleteMembership(selectedMember.teamId, selectedMember.$id);
showDelete = false;
dispatch('deleted');
addNotification({
type: 'success',
message: `${selectedMember.userName} was deleted from ${selectedMember.teamName}`
});
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
}
};
$: isUser = selectedMember.userId === $user.$id;
</script>
<Form on:submit={deleteMembership}>
<Modal bind:show={showDelete} warning>
<svelte:fragment slot="header">
{isUser ? 'Leave Organization' : 'Delete Member'}
</svelte:fragment>
<p>
{isUser
? `Are you sure you want to leave '${selectedMember.teamName}'?`
: `Are you sure you want to delete ${selectedMember.userName} from '${selectedMember.teamName}'?`}
</p>
<svelte:fragment slot="footer">
<Button text on:click={() => (showDelete = false)}>Cancel</Button>
<Button secondary submit>{isUser ? 'Leave' : 'Delete'}</Button>
</svelte:fragment>
</Modal>
</Form>
@@ -0,0 +1,48 @@
<script lang="ts">
import { Modal } from '$lib/components';
import { Button, Form } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
import { newOrgModal, organization, organizationList } from '$lib/stores/organization';
import { goto } from '$app/navigation';
import { base } from '$app/paths';
export let showDelete = false;
const deleteOrg = async () => {
try {
await sdkForConsole.teams.delete($organization.$id);
addNotification({
type: 'success',
message: `${$organization.name} has been deleted`
});
if ($organizationList?.total > 1) {
await organizationList.load();
goto(`${base}/console/organization-${$organizationList.teams[0].$id}`);
} else {
newOrgModal.set(true);
goto(`${base}/console`);
}
showDelete = false;
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
}
};
</script>
<Form on:submit={deleteOrg}>
<Modal bind:show={showDelete} warning>
<svelte:fragment slot="header">Delete Organization</svelte:fragment>
<p>
Are you sure you want to delete <b>{$organization.name}</b>? All projects ({$organization.total})
and data associated with this organization will be deleted. This action is irreversible.
</p>
<svelte:fragment slot="footer">
<Button text on:click={() => (showDelete = false)}>Cancel</Button>
<Button secondary submit>Delete</Button>
</svelte:fragment>
</Modal>
</Form>
@@ -0,0 +1,150 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { base } from '$app/paths';
import { Pill } from '$lib/elements';
import { Bucket, EmptyBucket, Empty, Pagination } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import type { Models } from '@aw-labs/appwrite-console';
import CreateOrganization from '../_createOrganization.svelte';
import CreateProject from './_createProject.svelte';
import { projectList } from '$lib/stores/organization';
import { project } from '../project-[project]/store';
import { onMount } from 'svelte';
import { page } from '$app/stores';
let projects: Models.Project[] = [];
$: organizationId = $page.params.organization;
onMount(async () => {
await projectList.load('', undefined, offset);
projects = $projectList?.projects?.filter((n) => n.teamId === organizationId);
});
let showCreate = false;
let addOrganization = false;
let offset = 0;
const limit = 6;
const projectCreated = async (event: CustomEvent<Models.Project>) => {
await project.load(event.detail.$id);
await goto(`${base}/console/project-${event.detail.$id}`);
};
const getPlatformInfo = (platform: string) => {
let name: string, icon: string;
if (platform.includes('flutter')) {
name = 'Flutter';
icon = 'flutter';
} else if (platform.includes('apple')) {
name = 'Apple';
icon = 'apple';
} else if (platform.includes('android')) {
name = 'Android';
icon = 'android';
} else if (platform.includes('unity')) {
name = 'Unity';
icon = 'unity';
} else if (platform.includes('web')) {
name = 'Web';
icon = 'code';
} else {
name = 'Unknown';
icon = 'unknown';
}
return { name, icon };
};
// $: projectList.load('', limit, offset);
$: projects = $projectList?.projects?.filter((a) => a.teamId === organizationId);
</script>
<Container>
<div class="u-flex u-gap-12 common-section u-main-space-between">
<h2 class="heading-level-5">Projects</h2>
<Button
on:click={() => {
showCreate = true;
}}>
<span class="icon-plus" aria-hidden="true" /> <span class="text">Create project</span>
</Button>
</div>
{#if projects?.length}
<ul
class="grid-box common-section u-margin-block-start-32"
style={`--grid-gap:1.5rem; --grid-item-size:${
projects.length > 3 ? '22rem' : '25rem'
};`}>
{#each projects as project, index}
{#if index >= offset && index < limit + offset}
<Bucket href={`${base}/console/project-${project.$id}`}>
<svelte:fragment slot="eyebrow"
>{project?.platforms?.length ? project?.platforms?.length : 'No'} apps</svelte:fragment>
<svelte:fragment slot="title">
{project.name}
</svelte:fragment>
{@const platformList = project.platforms.map((platform) => platform.type)}
{@const platforms = Array.from(new Set(platformList))}
{#each platforms as platform, i}
{#if i < 3}
<Pill>
<span
class={`icon-${getPlatformInfo(platform).icon}`}
aria-hidden="true" />
{getPlatformInfo(platform).name}
</Pill>
{/if}
{/each}
{#if platforms?.length > 3}
<Pill>
+{project.platforms.length - 3}
</Pill>
{/if}
</Bucket>
{/if}
{/each}
{#if projects.length < limit + offset && (projects.length % 2 !== 0 || projects.length % 4 === 0)}
<EmptyBucket on:click={() => (showCreate = true)}>
<div class="common-section">
<Button secondary round>
<i class="icon-plus" />
</Button>
</div>
<div class="common-section">
<p>Create a new project</p>
</div>
</EmptyBucket>
{/if}
</ul>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {projects.length}</p>
<Pagination {limit} bind:offset sum={projects.length} />
</div>
{:else}
<Empty dashed centered>
<div class="bucket">
<div class="u-flex u-flex-vertical u-cross-center ">
<div class="common-section">
<Button secondary round on:click={() => (showCreate = true)}>
<i class="icon-plus" />
</Button>
</div>
<div class="common-section">
<p>Create a new project</p>
</div>
</div>
</div>
</Empty>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {projects?.length}</p>
<Pagination {limit} bind:offset sum={projects?.length} />
</div>
{/if}
</Container>
<CreateOrganization bind:show={addOrganization} />
<CreateProject bind:show={showCreate} teamId={organizationId} on:created={projectCreated} />
@@ -0,0 +1,116 @@
<script lang="ts">
import {
Table,
TableHeader,
TableBody,
TableCellHead,
TableCell,
TableCellText,
TableRow
} from '$lib/elements/table';
import { Avatar, Pagination } from '$lib/components';
import { Pill } from '$lib/elements';
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import Delete from './_deleteMember.svelte';
import { organization, memberList, newMemberModal } from '$lib/stores/organization';
import { sdkForConsole } from '$lib/stores/sdk';
import type { Models } from '@aw-labs/appwrite-console';
import { pageLimit } from '$lib/stores/layout';
import { page } from '$app/stores';
let search = '';
let offset: number = null;
let selectedMember: Models.Membership;
let showDelete = false;
const url = `${$page.url.origin}/console/`;
const getAvatar = (name: string) =>
sdkForConsole.avatars.getInitials(name, 120, 120).toString();
const deleted = () => memberList.load($organization.$id, search, $pageLimit, offset ?? 0);
const resend = async (member: Models.Membership) =>
await sdkForConsole.teams.createMembership(
$organization.$id,
member.userEmail,
member.roles,
url,
member.userName
);
$: if (search) offset = 0;
$: memberList.load($organization.$id, search, $pageLimit, offset ?? 0);
</script>
<Container>
{#if $memberList?.total}
<div class="u-flex u-gap-12 common-section u-main-space-between">
<h2 class="heading-level-5">Members</h2>
<Button
on:click={() => {
newMemberModal.set(true);
}}>
<span class="icon-plus" aria-hidden="true" />
<span class="text">Invite</span>
</Button>
</div>
<Table>
<TableHeader>
<TableCellHead>Name</TableCellHead>
<TableCellHead>Email</TableCellHead>
<TableCellHead width={100}>Role</TableCellHead>
<TableCellHead width={30} />
</TableHeader>
<TableBody>
{#each $memberList.memberships as member}
<TableRow>
<TableCell title="Name">
<div class="u-flex u-gap-12 u-cross-center">
<Avatar
size={40}
src={getAvatar(member.userName)}
name={member.userName} />
<span class="text u-trim"
>{member.userName ? member.userName : 'n/a'}</span>
{#if member.invited && !member.joined}
<Pill warning>Pending</Pill>
{/if}
</div>
</TableCell>
<TableCellText title="Email">{member.userEmail}</TableCellText>
<TableCell title="Roles">
{#if member.invited && !member.joined}
<Button secondary on:click={() => resend(member)}>Resend</Button>
{:else}
{member.roles}
{/if}
</TableCell>
<TableCell>
<button
class="button is-only-icon is-text"
aria-label="Delete item"
disabled={$memberList.total === 1}
on:click={() => {
selectedMember = member;
showDelete = true;
}}>
<span class="icon-trash" aria-hidden="true" />
</button>
</TableCell>
</TableRow>
{/each}
</TableBody>
</Table>
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {$memberList.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={$memberList.total} />
</div>
{/if}
</Container>
{#if selectedMember}
<Delete {selectedMember} bind:showDelete on:deleted={() => deleted()} />
{/if}
@@ -0,0 +1,104 @@
<script lang="ts">
import { CardGrid, Box, AvatarGroup } from '$lib/components';
import { InputText, Form, Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import { addNotification } from '$lib/stores/notifications';
import { sdkForConsole } from '$lib/stores/sdk';
import { organization, memberList } from '$lib/stores/organization';
import { title, breadcrumbs } from '$lib/stores/layout';
import Delete from './_deleteOrganization.svelte';
let name: string = $organization.name;
let showDelete = false;
async function updateName() {
try {
await sdkForConsole.teams.update($organization.$id, name);
$organization.name = name;
title.set(name);
const breadcrumb = $breadcrumbs.get(0);
breadcrumb.title = name;
$breadcrumbs = $breadcrumbs.set($breadcrumbs.size, breadcrumb);
addNotification({
message: 'Name has been updated',
type: 'success'
});
} catch (error) {
addNotification({
message: error.message,
type: 'error'
});
}
}
organization.subscribe((org) => {
name = org?.name;
});
let avatars = [];
let avatarsTotal = 0;
memberList.subscribe((value) => {
if (value?.total > 0) {
avatarsTotal = value.total;
avatars = value.memberships.map((team) => {
return {
name: team.userName,
img: sdkForConsole.avatars.getInitials(team.userName, 120, 120).toString()
};
});
}
});
</script>
<Container>
{#if $organization}
<Form on:submit={updateName}>
<CardGrid>
<h6 class="heading-level-7">Update Name</h6>
<svelte:fragment slot="aside">
<ul>
<InputText
id="name"
label="Name"
placeholder="Enter name"
autocomplete={false}
bind:value={name} />
</ul>
</svelte:fragment>
<svelte:fragment slot="actions">
<Button disabled={name === $organization.name || !name} submit>Update</Button>
</svelte:fragment>
</CardGrid>
</Form>
<CardGrid>
<div>
<h6 class="heading-level-7">Delete Organization</h6>
</div>
<p>
The organization will be permanently deleted, including all projects and data
associated with this organization. This action is irreversible.
</p>
<svelte:fragment slot="aside">
<Box>
<svelte:fragment slot="image">
<AvatarGroup {avatars} total={avatarsTotal} />
</svelte:fragment>
<svelte:fragment slot="title">
<h6 class="u-bold">{$organization.name}</h6>
</svelte:fragment>
<p>{$organization.total} projects</p>
</Box>
</svelte:fragment>
<svelte:fragment slot="actions">
<Button secondary on:click={() => (showDelete = true)}>Delete</Button>
</svelte:fragment>
</CardGrid>
{/if}
</Container>
<Delete bind:showDelete />
@@ -4,7 +4,8 @@
import { sdkForConsole, setProject } from '$lib/stores/sdk';
import { collection } from './databases/database/[database]/collection/[collection]/store';
import { UploadBox } from '$lib/components';
import { organisation, project } from './store';
import { project } from './store';
import { organization } from '$lib/stores/organization';
import { onMount } from 'svelte';
import { afterNavigate } from '$app/navigation';
import { updateLayout } from '$lib/stores/layout';
@@ -47,28 +48,27 @@
afterNavigate(handle);
let loaded = false;
const path = 'console';
async function handle(event = null) {
if ($project?.$id !== projectId) {
setProject(projectId);
await project.load(projectId);
}
if ($organisation?.$id !== $project.teamId) {
await organisation.load($project.teamId);
if ($organization?.$id !== $project?.teamId) {
await organization.load($project.teamId);
}
}
updateLayout({
navigate: event,
title: $project.name,
level: 2,
level: 1,
breadcrumbs: [
{
href: path,
title: $organisation.name,
level: 1
href: 'console',
title: $organization.name,
level: 0
},
{
href: $project.$id,
href: `project-${$project.$id}`,
title: $project.name
}
]
@@ -30,7 +30,7 @@
const project = $page.params.project;
const getAvatar = (name: string) => sdkForProject.avatars.getInitials(name, 32, 32).toString();
const userCreated = async (event: CustomEvent<Models.User<Record<string, unknown>>>) => {
await goto(`${base}/console/${project}/authentication/user/${event.detail.$id}`);
await goto(`${base}/console/project-${project}/authentication/user/${event.detail.$id}`);
};
$: if (search) offset = 0;
@@ -64,7 +64,7 @@
<TableBody>
{#each $usersList.users as user}
<TableRowLink
href={`${base}/console/${project}/authentication/user/${user.$id}`}>
href={`${base}/console/project-${project}/authentication/user/${user.$id}`}>
<TableCell title="Name">
<div class="u-flex u-gap-12 u-cross-center">
<Avatar size={32} src={getAvatar(user.name)} name={user.name} />
@@ -29,7 +29,7 @@
const project = $page.params.project;
const getAvatar = (name: string) => sdkForProject.avatars.getInitials(name, 32, 32).toString();
const teamCreated = async (event: CustomEvent<Models.Team>) => {
await goto(`${base}/console/${project}/authentication/teams/${event.detail.$id}`);
await goto(`${base}/console/project-${project}/authentication/teams/${event.detail.$id}`);
};
$: if (search) offset = 0;
@@ -61,7 +61,7 @@
<TableBody>
{#each $teamsList.teams as team}
<TableRowLink
href={`${base}/console/${project}/authentication/teams/${team.$id}`}>
href={`${base}/console/project-${project}/authentication/teams/${team.$id}`}>
<TableCell title="ID">
<div class="u-flex u-gap-12">
<Avatar size={32} name={team.name} src={getAvatar(team.name)} />
@@ -21,7 +21,7 @@
navigate: event,
level: 4,
title: $team.name,
back: `${base}/console/${$page.params.project}/authentication/teams`,
back: `${base}/console/project-${$page.params.project}/authentication/teams`,
breadcrumbs: {
title: $team.name,
href: `teams/${teamId}`
@@ -15,7 +15,7 @@
let error: string;
const create = async () => {
const url = `${$page.url.origin}/console/${$page.params.project}/authentication/teams/${$page.params.team}/members`;
const url = `${$page.url.origin}/console/project-${$page.params.project}/authentication/teams/${$page.params.team}/members`;
try {
const user = await sdkForProject.teams.createMembership(
@@ -23,7 +23,7 @@
showDelete = false;
dispatch('deleted');
await goto(
`${base}/console/${$page.params.project}/authentication/user/${selectedMembership.userId}/memberships`
`${base}/console/project-${$page.params.project}/authentication/teams/${selectedMembership.teamId}/members`
);
} catch (error) {
addNotification({
@@ -15,7 +15,7 @@
try {
await sdkForProject.teams.delete(team.$id);
showDelete = false;
await goto(`${base}/console/${$page.params.project}/authentication/teams`);
await goto(`${base}/console/project-${$page.params.project}/authentication/teams`);
} catch (error) {
addNotification({
type: 'error',
@@ -8,24 +8,20 @@
TableHeader,
TableRow,
TableCellHead,
TableCell,
TableCellText
} from '$lib/elements/table';
import { Container } from '$lib/layout';
import { toLocaleDateTime } from '$lib/helpers/date';
import { sdkForProject } from '$lib/stores/sdk';
import { app } from '$lib/stores/app';
import { pageLimit } from '$lib/stores/layout';
let offset = 0;
$: request = sdkForProject.teams.listLogs($page.params.team, $pageLimit, offset);
let browsers = {
firefox: 'firefox',
chrome: 'chrome',
safari: 'safari',
opera: 'opera',
edge: 'edge'
const getBrowser = (clientCode: string) => {
return sdkForProject.avatars.getBrowser(clientCode, 80, 80);
};
</script>
@@ -45,29 +41,33 @@
<TableBody>
{#each response.logs as log}
<TableRow>
<TableCellText title="Client">
<div class="u-flex u-cross-center u-gap-12">
<div class="avatar is-small">
{#if browsers[log.clientName.toLocaleLowerCase()]}
<TableCell title="Client">
{#if log.clientName}
<div class="u-flex u-cross-center u-gap-12">
<div class="avatar is-small">
<img
height="20"
width="20"
src={`/icons/${
$app.themeInUse
}/color/${log?.clientName.toLocaleLowerCase()}.svg`}
src={getBrowser(log.clientCode).toString()}
alt={log.clientName} />
{:else}
<span class="icon-globe-alt" />
{/if}
</div>
<p class="text u-trim">
{log.clientName}
{log.clientVersion}
on {log.osName}
{log.osVersion}
</p>
</div>
<p class="text u-trim">
{log.clientName}
{log.clientVersion}
on {log.osName}
{log.osVersion}
</p>
</div>
</TableCellText>
{:else}
<div class="u-flex u-cross-center u-gap-12">
<p class="text u-trim">
<span class="avatar is-color-empty" />
Unknown
</p>
</div>
{/if}
</TableCell>
<TableCellText title="Event">{log.event}</TableCellText>
<TableCellText title="Location">
@@ -96,9 +96,7 @@
</div>
</Empty>
{/if}
<div
class="u-flex u-margin-block-start-32
u-main-space-between">
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {response.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={response.total} />
</div>
@@ -38,7 +38,7 @@
const memberCreated = async (event: CustomEvent<Models.Membership>) => {
memberships.load($page.params.team, search, $pageLimit, offset ?? 0);
await goto(
`${base}/console/${project}/authentication/teams/${event.detail.teamId}/members`
`${base}/console/project-${project}/authentication/teams/${event.detail.teamId}/members`
);
};
</script>
@@ -61,7 +61,7 @@
<TableBody>
{#each $memberships.memberships as membership}
<TableRowLink
href={`${base}/console/${project}/authentication/user/${membership.userId}`}>
href={`${base}/console/project-${project}/authentication/user/${membership.userId}`}>
<TableCellText title="Name">
<div class="u-flex u-gap-12">
<Avatar
@@ -25,7 +25,7 @@
title: $user.name,
href: `user/${userId}`
},
back: `${base}/console/${$page.params.project}/authentication`,
back: `${base}/console/project-${$page.params.project}/authentication`,
copy: {
text: 'User ID',
value: userId
@@ -15,7 +15,7 @@
await sdkForProject.teams.deleteMembership('tmpstring', 'tmpstring2');
showDeleteAll = false;
await goto(
`${base}/console/${$page.params.project}/authentication/${$user.$id}/membeships`
`${base}/console/project-${$page.params.project}/authentication/${$user.$id}/membeships`
);
} catch (error) {
addNotification({
@@ -23,7 +23,7 @@
showDelete = false;
dispatch('deleted');
await goto(
`${base}/console/${$page.params.project}/authentication/teams/${selectedMembership.teamId}/members`
`${base}/console/project-${$page.params.project}/authentication/user/${selectedMembership.userId}/memberships`
);
} catch (error) {
addNotification({
@@ -19,7 +19,7 @@
type: 'success',
message: `${$user.name} has been deleted`
});
await goto(`${base}/console/${$page.params.project}/authentication`);
await goto(`${base}/console/project-${$page.params.project}/authentication`);
} catch (error) {
addNotification({
type: 'error',
@@ -8,24 +8,20 @@
TableHeader,
TableRow,
TableCellHead,
TableCell,
TableCellText
} from '$lib/elements/table';
import { Container } from '$lib/layout';
import { toLocaleDateTime } from '$lib/helpers/date';
import { sdkForProject } from '$lib/stores/sdk';
import { app } from '$lib/stores/app';
import { pageLimit } from '$lib/stores/layout';
let offset = 0;
const limit = 25;
$: request = sdkForProject.users.getLogs($page.params.user, limit, offset);
$: request = sdkForProject.users.getLogs($page.params.user, $pageLimit, offset);
let browsers = {
firefox: 'firefox',
chrome: 'chrome',
safari: 'safari',
opera: 'opera',
edge: 'edge'
const getBrowser = (clientCode: string) => {
return sdkForProject.avatars.getBrowser(clientCode, 80, 80);
};
</script>
@@ -45,38 +41,38 @@
<TableBody>
{#each response.logs as log}
<TableRow>
<TableCellText title="Client">
<div class="u-flex u-cross-center u-gap-12">
<div class="avatar is-small">
{#if browsers[log.clientName.toLocaleLowerCase()]}
<TableCell title="Client">
{#if log.clientName}
<div class="u-flex u-cross-center u-gap-12">
<div class="avatar is-small">
<img
height="20"
width="20"
src={`/icons/${
$app.themeInUse
}/color/${log?.clientName.toLocaleLowerCase()}.svg`}
src={getBrowser(log.clientCode).toString()}
alt={log.clientName} />
{:else}
<span class="icon-globe-alt" />
{/if}
</div>
<p class="text u-trim">
{log.clientName}
{log.clientVersion}
on {log.osName}
{log.osVersion}
</p>
</div>
<p class="text u-trim">
{log.clientName}
{log.clientVersion}
on {log.osName}
{log.osVersion}
</p>
</div>
</TableCellText>
{:else}
<div class="u-flex u-cross-center u-gap-12">
<p class="text u-trim">
<span class="avatar is-color-empty" />
Unknown
</p>
</div>
{/if}
</TableCell>
<TableCellText title="Event">{log.event}</TableCellText>
<TableCellText title="Location">
{#if log.countryCode !== '--'}
<img
src={sdkForProject.avatars
.getFlag(log.countryCode, 32, 32)
.toString()}
alt={log.countryName} />{log.countryName}
{log.countryName}
{:else}
Unknown
{/if}
@@ -103,11 +99,9 @@
</div>
</Empty>
{/if}
<div
class="u-flex u-margin-block-start-32
u-main-space-between">
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {response.total}</p>
<Pagination {limit} bind:offset sum={response.total} />
<Pagination limit={$pageLimit} bind:offset sum={response.total} />
</div>
{/await}
</Container>
@@ -51,7 +51,7 @@
<TableBody>
{#each response.memberships as membership}
<TableRowLink
href={`${base}/console/${project}/authentication/teams/${membership.teamId}`}>
href={`${base}/console/project-${project}/authentication/teams/${membership.teamId}`}>
<TableCellText title="Name">
<div class="u-flex u-gap-12">
<Avatar
@@ -0,0 +1,116 @@
<script lang="ts">
import { page } from '$app/stores';
import { Empty, Pagination } from '$lib/components';
import {
Table,
TableBody,
TableHeader,
TableRow,
TableCellHead,
TableCell,
TableCellText
} from '$lib/elements/table';
import { Pill } from '$lib/elements';
import { Button } from '$lib/elements/forms';
import { Container } from '$lib/layout';
import { sdkForProject } from '$lib/stores/sdk';
import DeleteAllSessions from './_deleteAllSessions.svelte';
import DeleteSessions from './_deleteSession.svelte';
import { pageLimit } from '$lib/stores/layout';
import { onMount } from 'svelte';
import type { Models } from '@aw-labs/appwrite-console';
let offset = 0;
let showDelete = false;
let showDeleteAll = false;
let selectedSessionId: string = null;
let sessionList: Models.SessionList = null;
onMount(async () => {
sessionList = await sdkForProject.users.getSessions($page.params.user);
});
const getBrowser = (clientCode: string) => {
return sdkForProject.avatars.getBrowser(clientCode, 40, 40);
};
</script>
<Container>
{#if sessionList?.total}
<div class="u-flex u-main-end common-section">
<Button secondary on:click={() => (showDeleteAll = true)}>
<span class="text">Delete All</span>
</Button>
</div>
<Table>
<TableHeader>
<TableCellHead>Browser and Device</TableCellHead>
<TableCellHead width={140}>Session</TableCellHead>
<TableCellHead width={140}>Location</TableCellHead>
<TableCellHead width={140}>IP</TableCellHead>
<TableCellHead width={30} />
</TableHeader>
<TableBody>
{#each sessionList.sessions as session}
<TableRow>
<TableCell title="Client">
<div class="u-flex u-gap-12">
<div class="image-item">
<img
height="20"
width="20"
src={getBrowser(session.clientCode).toString()}
alt={session.clientName} />
</div>
<p class="text">
{session.clientName}
{session.clientVersion} on {session.osName}
{session.osVersion}
</p>
{#if session.current}
<Pill success>current session</Pill>
{/if}
</div>
</TableCell>
<TableCellText title="Session">{session.clientType}</TableCellText>
<TableCellText title="Location">{session.countryName}</TableCellText>
<TableCellText title="IP">{session.ip}</TableCellText>
<TableCellText title="">
<button
class="button is-only-icon is-text"
aria-label="Delete item"
on:click={() => {
selectedSessionId = session.$id;
showDelete = true;
}}>
<span class="icon-trash" aria-hidden="true" />
</button>
</TableCellText>
</TableRow>
{/each}
</TableBody>
</Table>
{:else}
<Empty centered>
<div class="u-flex u-flex-vertical u-cross-center">
<div class="common-section">
<p>No session available</p>
</div>
<div class="common-section">
<Button
external
secondary
href="https://appwrite.io/docs/server/authentication?sdk=nodejs-default#usersGetSessions"
>Documentation</Button>
</div>
</div>
</Empty>
{/if}
<div class="u-flex u-margin-block-start-32 u-main-space-between">
<p class="text">Total results: {sessionList?.total}</p>
<Pagination limit={$pageLimit} bind:offset sum={sessionList?.total} />
</div>
</Container>
<DeleteSessions {selectedSessionId} bind:showDelete />
<DeleteAllSessions bind:showDeleteAll />
@@ -24,7 +24,7 @@
updateLayout({
navigate: event,
title: $collection.name,
back: `${base}/console/${$page.params.project}/databases/database/${databaseId}`,
back: `${base}/console/project-${$page.params.project}/database`,
copy: {
text: 'Collection ID',
value: collectionId
@@ -0,0 +1,78 @@
<script lang="ts">
import { page } from '$app/stores';
import { Back, Card } from '$lib/components';
import { Button, Form } from '$lib/elements/forms';
import { sdkForProject } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import { collection } from '../store';
import { doc } from './[document]/store';
import { addNotification } from '$lib/stores/notifications';
import Document from './[document]/_document.svelte';
import { goto } from '$app/navigation';
import InputCustomId from '$lib/elements/forms/inputCustomId.svelte';
import { Container, Cover } from '$lib/layout';
import { base } from '$app/paths';
$: projectId = $page.params.project;
onMount(() => {
doc.set({
$collection: $page.params.collection,
$id: null,
$createdAt: null,
$updatedAt: null,
$read: [],
$write: []
});
});
const createDocument = async () => {
try {
const created = await sdkForProject.databases.createDocument(
$collection.$id,
$doc.$id,
{
...$doc,
$id: undefined
},
$doc.$read,
$doc.$write
);
addNotification({
message: 'Document was created!',
type: 'success'
});
await goto(
`${base}/console/project-${projectId}/database/collection/${created.$collection}/document/${created.$id}`
);
} catch (error) {
addNotification({
message: error.message,
type: 'error'
});
}
};
</script>
<svelte:head>
<title>Appwrite - Document</title>
</svelte:head>
{#if $doc && $collection}
<Cover>
<Back href={`${base}/console/project-${projectId}/database/collection/${$collection.$id}`}>
Collection - {$collection.name}
</Back>
<h1>Create Document</h1>
</Cover>
<Container>
<Card>
<Form on:submit={createDocument}>
<InputCustomId id="id" label="Document ID" bind:value={$doc.$id} />
<Document />
<Button submit>Create</Button>
</Form>
</Card>
</Container>
{:else}
<div aria-busy="true" />
{/if}

Some files were not shown because too many files have changed in this diff Show More