correct prettier

This commit is contained in:
Jesse Winton
2024-08-27 15:04:57 -04:00
parent 687fa7a28c
commit 9a74791115
37 changed files with 3927 additions and 3806 deletions

View File

@@ -5,5 +5,6 @@
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-tailwindcss", "prettier-plugin-svelte"],
"pluginSearchDirs": ["."],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

View File

@@ -1,268 +1,269 @@
<script lang="ts">
import { onMount } from 'svelte';
import LockSvg from './(assets)/lock.svg';
import SafetySvg from './(assets)/safety.svg';
import { animate, inView, spring } from 'motion';
import { onMount } from "svelte";
import LockSvg from "./(assets)/lock.svg";
import SafetySvg from "./(assets)/safety.svg";
import { animate, inView, spring } from "motion";
export let delay = 1;
export let delay = 1;
onMount(() => {
inView('#enum-anim', () => {
animate(
'#enum-anim .icon-wrapper:not(:last-child)',
{
opacity: [0, 1]
},
{
easing: spring({ mass: 1, stiffness: 100, damping: 15 }),
delay: delay
}
);
animate(
'#enum-anim .icon-wrapper:last-child',
{
opacity: [0, 1],
y: 57
},
{
easing: spring({ mass: 1, stiffness: 100, damping: 15 }),
delay: delay
}
);
onMount(() => {
inView("#enum-anim", () => {
animate(
"#enum-anim .icon-wrapper:not(:last-child)",
{
opacity: [0, 1],
},
{
easing: spring({ mass: 1, stiffness: 100, damping: 15 }),
delay: delay,
},
);
animate(
"#enum-anim .icon-wrapper:last-child",
{
opacity: [0, 1],
y: 57,
},
{
easing: spring({ mass: 1, stiffness: 100, damping: 15 }),
delay: delay,
},
);
[...new Array(4)].forEach((_, i) => {
animate(
`#enum-anim .line:nth-child(${i + 1})`,
{
opacity: [0, 1]
},
{
easing: 'ease-out',
delay: delay + (0.2 * i + 1)
}
);
});
});
[...new Array(4)].forEach((_, i) => {
animate(
`#enum-anim .line:nth-child(${i + 1})`,
{
opacity: [0, 1],
},
{
easing: "ease-out",
delay: delay + (0.2 * i + 1),
},
);
});
});
});
</script>
<div id="enum-anim" class="component">
<div class="window">
<div class="buttons">
<div class="circle" />
<div class="circle" />
<div class="circle" />
</div>
<div class="window-bg" />
<div class="window">
<div class="buttons">
<div class="circle" />
<div class="circle" />
<div class="circle" />
</div>
<div class="window-bg" />
<div class="lines">
<!-- eslint-disable-next-line @typescript-eslint/no-unused-vars -->
{#each { length: 4 } as _}
<div class="line">
<div class="diamond-wrapper">
<div class="diamond" />
</div>
<div class="equals" />
<div class="rectangle" />
</div>
{/each}
<div class="lines">
<!-- eslint-disable-next-line @typescript-eslint/no-unused-vars -->
{#each { length: 4 } as _}
<div class="line">
<div class="diamond-wrapper">
<div class="diamond" />
</div>
<div class="equals" />
<div class="rectangle" />
</div>
{/each}
</div>
</div>
<div class="icon-wrapper">
<img src={LockSvg} alt="lock" />
</div>
<div class="icon-wrapper">
<img src={SafetySvg} alt="safety" />
</div>
<div class="icon-wrapper">
<img src={LockSvg} alt="lock" />
</div>
<div class="icon-wrapper">
<img src={SafetySvg} alt="safety" />
</div>
</div>
<style lang="scss">
@use '$scss/abstract/mixins/border-gradient' as gradients;
@use "$scss/abstract/mixins/border-gradient" as gradients;
.component {
width: 297px;
height: 204.97px;
position: relative;
.component {
width: 297px;
height: 204.97px;
position: relative;
}
.window {
width: 238.44px;
height: 204.97px;
left: 58.56px;
top: -0px;
position: absolute;
background: linear-gradient(
180deg,
rgba(34.63, 34.63, 36.77, 0.4) 0%,
rgba(34.63, 34.63, 36.77, 0.24) 100%
);
box-shadow: 0px 2.247819185256958px 4.495638370513916px rgba(0, 0, 0, 0.02);
backdrop-filter: blur(22.31px);
@include gradients.border-gradient;
--m-border-radius: 12px;
--m-border-gradient-before: linear-gradient(
180deg,
rgba(255, 255, 255, 0.14) 0%,
rgba(255, 255, 255, 0) 106.54%
);
}
.buttons {
display: flex;
gap: 5px;
left: 10.7px;
top: 10.69px;
position: absolute;
}
.circle {
width: 8px;
height: 8px;
background: #ededf0;
border-radius: 9999px;
}
.window-bg {
width: 227.28px;
height: 170.11px;
left: 5.58px;
top: 29.28px;
position: absolute;
background: rgba(255, 255, 255, 0.04);
box-shadow: 0px 1.7886674404144287px 3.5773348808288574px
rgba(0, 0, 0, 0.02);
border-radius: 11.15px;
}
.lines {
left: 22.31px;
top: 46.01px;
position: absolute;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
gap: 11.15px;
display: inline-flex;
}
.line {
justify-content: flex-start;
align-items: center;
gap: 7.48px;
display: inline-flex;
opacity: 0;
&:nth-child(2) {
* {
opacity: 0.4;
}
.rectangle {
width: 100px;
}
}
.window {
width: 238.44px;
height: 204.97px;
left: 58.56px;
top: -0px;
&:nth-child(3) {
* {
opacity: 0.2;
}
.rectangle {
width: 114px;
}
}
&:nth-child(4) {
* {
opacity: 0.1;
}
}
.diamond-wrapper {
width: 25.64px;
height: 25.64px;
position: relative;
.diamond {
width: 16.73px;
height: 16.73px;
left: 12.83px;
top: 0.74px;
position: absolute;
background: linear-gradient(
180deg,
rgba(34.63, 34.63, 36.77, 0.4) 0%,
rgba(34.63, 34.63, 36.77, 0.24) 100%
);
box-shadow: 0px 2.247819185256958px 4.495638370513916px rgba(0, 0, 0, 0.02);
backdrop-filter: blur(22.31px);
@include gradients.border-gradient;
--m-border-radius: 12px;
--m-border-gradient-before: linear-gradient(
180deg,
rgba(255, 255, 255, 0.14) 0%,
rgba(255, 255, 255, 0) 106.54%
);
transform: rotate(45deg);
transform-origin: 0 0;
background: linear-gradient(180deg, #fd366e 0%, #fd576c 100%);
border-radius: 4.18px;
}
}
.buttons {
display: flex;
gap: 5px;
left: 10.7px;
top: 10.69px;
position: absolute;
}
.equals {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 8.55px;
height: 6px;
gap: 2px;
.circle {
width: 8px;
height: 8px;
&::before,
&::after {
background: #ededf0;
border-radius: 9999px;
border-radius: 35.26px;
width: 8.55px;
height: 5.34px;
content: "";
}
}
.window-bg {
width: 227.28px;
height: 170.11px;
left: 5.58px;
top: 29.28px;
position: absolute;
background: rgba(255, 255, 255, 0.04);
box-shadow: 0px 1.7886674404144287px 3.5773348808288574px rgba(0, 0, 0, 0.02);
border-radius: 11.15px;
.rectangle {
width: 139.98px;
height: 17.1px;
background: linear-gradient(
90deg,
rgba(124, 103, 254, 0.7) 0%,
rgba(124, 103, 254, 0) 100%
);
border-radius: 105.78px;
}
}
.lines {
left: 22.31px;
top: 46.01px;
position: absolute;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
gap: 11.15px;
display: inline-flex;
}
.line {
justify-content: flex-start;
align-items: center;
gap: 7.48px;
display: inline-flex;
opacity: 0;
&:nth-child(2) {
* {
opacity: 0.4;
}
.rectangle {
width: 100px;
}
}
&:nth-child(3) {
* {
opacity: 0.2;
}
.rectangle {
width: 114px;
}
}
&:nth-child(4) {
* {
opacity: 0.1;
}
}
.diamond-wrapper {
width: 25.64px;
height: 25.64px;
position: relative;
.diamond {
width: 16.73px;
height: 16.73px;
left: 12.83px;
top: 0.74px;
position: absolute;
transform: rotate(45deg);
transform-origin: 0 0;
background: linear-gradient(180deg, #fd366e 0%, #fd576c 100%);
border-radius: 4.18px;
}
}
.equals {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 8.55px;
height: 6px;
gap: 2px;
&::before,
&::after {
background: #ededf0;
border-radius: 35.26px;
width: 8.55px;
height: 5.34px;
content: '';
}
}
.rectangle {
width: 139.98px;
height: 17.1px;
background: linear-gradient(
90deg,
rgba(124, 103, 254, 0.7) 0%,
rgba(124, 103, 254, 0) 100%
);
border-radius: 105.78px;
}
}
.icon-wrapper {
@include gradients.border-gradient;
--m-border-radius: 1000px;
--m-border-gradient-before: linear-gradient(
-45deg,
rgba(255, 255, 255, 0.14) 0%,
rgba(255, 255, 255, 0) 106.54%
);
width: 66.93px;
height: 66.93px;
left: 0px;
top: 0px;
position: absolute;
background: linear-gradient(
-45deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0.04) 62%
);
border-radius: 9999px;
backdrop-filter: blur(22.16px);
display: grid;
place-items: center;
z-index: 10;
opacity: 0;
&:last-child {
z-index: 1;
img {
translate: 2px;
}
}
.icon-wrapper {
@include gradients.border-gradient;
--m-border-radius: 1000px;
--m-border-gradient-before: linear-gradient(
-45deg,
rgba(255, 255, 255, 0.14) 0%,
rgba(255, 255, 255, 0) 106.54%
);
width: 66.93px;
height: 66.93px;
left: 0px;
top: 0px;
position: absolute;
background: linear-gradient(
-45deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0.04) 62%
);
border-radius: 9999px;
backdrop-filter: blur(22.16px);
display: grid;
place-items: center;
z-index: 10;
opacity: 0;
&:last-child {
z-index: 1;
img {
translate: 2px;
}
}
}
</style>

View File

@@ -1,351 +1,355 @@
<script lang="ts">
import { animate, inView, spring } from 'motion';
import { onMount } from 'svelte';
import { animate, inView, spring } from "motion";
import { onMount } from "svelte";
const id = 'integrations-anim';
export let delay = 1;
const id = "integrations-anim";
export let delay = 1;
onMount(async () => {
inView(`#${id}`, () => {
(async () => {
await animate(
`#${id} .rows > .item:nth-child(1)`,
{
opacity: [0, 1]
},
{
delay: delay,
duration: 0.2,
easing: 'ease-out'
}
).finished;
await animate(
`#${id} .rows > .item:nth-child(2)`,
{
opacity: [0, 1]
},
{
duration: 0.2,
easing: 'ease-out'
}
).finished;
await animate(
`#${id} .rows > .item:nth-child(3)`,
{
opacity: [0, 0.8]
},
{
duration: 0.2,
easing: 'ease-out'
}
).finished;
await animate(
`#${id} .rows > .item:nth-child(4)`,
{
opacity: [0, 0.6]
},
{
duration: 0.2,
easing: 'ease-out'
}
).finished;
onMount(async () => {
inView(`#${id}`, () => {
(async () => {
await animate(
`#${id} .rows > .item:nth-child(1)`,
{
opacity: [0, 1],
},
{
delay: delay,
duration: 0.2,
easing: "ease-out",
},
).finished;
await animate(
`#${id} .rows > .item:nth-child(2)`,
{
opacity: [0, 1],
},
{
duration: 0.2,
easing: "ease-out",
},
).finished;
await animate(
`#${id} .rows > .item:nth-child(3)`,
{
opacity: [0, 0.8],
},
{
duration: 0.2,
easing: "ease-out",
},
).finished;
await animate(
`#${id} .rows > .item:nth-child(4)`,
{
opacity: [0, 0.6],
},
{
duration: 0.2,
easing: "ease-out",
},
).finished;
await animate(
`#${id} .item.is-blue`,
{
opacity: [0, 1]
},
{
delay: 0.3,
duration: 0.2,
easing: 'ease-out'
}
).finished;
await animate(
`#${id} .item.is-blue`,
{
opacity: [0, 1],
},
{
delay: 0.3,
duration: 0.2,
easing: "ease-out",
},
).finished;
animate(
`#${id} .icon-token.bun`,
{
opacity: [0, 1],
y: [-10, 0]
},
{
easing: spring({ mass: 1, stiffness: 100, damping: 15 })
}
);
animate(
`#${id} .icon-token.bun`,
{
opacity: [0, 1],
y: [-10, 0],
},
{
easing: spring({ mass: 1, stiffness: 100, damping: 15 }),
},
);
animate(
`#${id} .icon-token.dart`,
{
opacity: [0, 1],
y: [-10, 0]
},
{
easing: spring({ mass: 1, stiffness: 100, damping: 15 })
}
);
})();
});
animate(
`#${id} .icon-token.dart`,
{
opacity: [0, 1],
y: [-10, 0],
},
{
easing: spring({ mass: 1, stiffness: 100, damping: 15 }),
},
);
})();
});
});
</script>
<div class="frame" {id}>
<div class="component">
<div class="overlap-group">
<div class="rows">
<div class="item">
<div class="item is-blue">
<div class="rectangle-wrapper"><div class="rectangle" /></div>
<div class="div" />
</div>
<div class="rectangle-wrapper"><div class="rectangle-2" /></div>
<div class="div" />
</div>
<div class="item">
<div class="rectangle-wrapper"><div class="rectangle-2" /></div>
<div class="div" />
</div>
<div class="item">
<div class="rectangle-wrapper"><div class="rectangle-2" /></div>
<div class="div" />
</div>
<div class="item">
<div class="rectangle-wrapper"><div class="rectangle-2" /></div>
<div class="div" />
</div>
</div>
<div class="component">
<div class="overlap-group">
<div class="rows">
<div class="item">
<div class="item is-blue">
<div class="rectangle-wrapper"><div class="rectangle" /></div>
<div class="div" />
</div>
<div class="rectangle-wrapper"><div class="rectangle-2" /></div>
<div class="div" />
</div>
<div class="circles">
<div class="circle" />
<div class="circle" />
<div class="circle" />
<div class="item">
<div class="rectangle-wrapper"><div class="rectangle-2" /></div>
<div class="div" />
</div>
<div class="item">
<div class="rectangle-wrapper"><div class="rectangle-2" /></div>
<div class="div" />
</div>
<div class="item">
<div class="rectangle-wrapper"><div class="rectangle-2" /></div>
<div class="div" />
</div>
</div>
</div>
<div class="icon-token bun">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 38 36" fill="none">
<g clip-path="url(#clip0_1104_153343)">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M15.639 30.5992C7.66287 28.4727 2.58822 21.4443 4.32475 14.9307C5.37274 10.9998 8.73409 7.96763 13.3118 6.83447C14.517 6.54291 15.5859 6.21151 16.5453 5.91402L16.8275 5.82658C17.3952 5.64952 17.9307 5.48493 18.4455 5.33587C20.0173 4.87915 21.32 4.64122 22.4771 4.9497C23.6342 5.25817 24.5189 5.99929 25.5807 7.09916C25.9067 7.42605 26.2274 7.7726 26.5688 8.14992L26.5854 8.16778C27.3802 9.02477 28.2776 9.99228 29.4877 11.147C32.8938 14.4086 34.3007 18.7077 33.2516 22.6426C31.5151 29.1562 23.6151 32.7256 15.639 30.5992ZM19.6352 8.58013C20.248 7.82555 20.6921 6.94739 20.9373 6.00561C20.9808 5.84234 21.2269 5.85676 21.2107 6.04439C21.1303 9.39681 18.9146 10.4781 17.4428 10.6445C17.2856 10.6623 17.2495 10.4479 17.3868 10.3779C18.2556 9.94792 19.0225 9.3347 19.6352 8.58013ZM22.0399 9.09713C22.1768 8.14195 22.1069 7.16899 21.835 6.24495L21.8392 6.22902C21.7973 6.06855 22.0177 5.95671 22.1048 6.09082C23.73 9.08328 22.3843 11.096 21.2209 11.9802C21.0952 12.0704 20.957 11.9055 21.0417 11.7788C21.5624 10.9671 21.903 10.0523 22.0399 9.09713ZM24.2583 9.00953C24.0063 8.07707 23.5584 7.2105 22.9446 6.46825L22.9488 6.45232C22.8438 6.32196 23.004 6.13433 23.1452 6.24022C25.8109 8.26888 25.3849 10.6932 24.6505 11.986C24.6345 12.017 24.6073 12.0408 24.5745 12.0523C24.5417 12.0637 24.5057 12.0621 24.4742 12.0476C24.4426 12.0332 24.4178 12.0071 24.405 11.9747C24.3921 11.9423 24.3922 11.9061 24.4051 11.8736C24.5603 10.9186 24.5102 9.94199 24.2583 9.00953ZM17.3486 7.96852C16.4706 8.39584 15.5135 8.63263 14.5398 8.66348C14.3858 8.66933 14.3256 8.87933 14.4769 8.91542C15.8773 9.38259 18.3444 9.32803 19.878 6.32461C19.956 6.17481 19.7455 6.05896 19.636 6.18334C19.0061 6.93294 18.2267 7.5412 17.3486 7.96852ZM13.5229 18.8432C13.9539 18.959 14.4097 18.9434 14.8327 18.7984C15.2558 18.6535 15.627 18.3857 15.8994 18.0289C16.1718 17.6722 16.3332 17.2425 16.3631 16.7943C16.393 16.3461 16.2901 15.8995 16.0674 15.5111C15.8447 15.1226 15.5123 14.8097 15.1121 14.612C14.712 14.4143 14.2621 14.3406 13.8194 14.4004C13.3768 14.4601 12.9612 14.6506 12.6254 14.9476C12.2896 15.2447 12.0485 15.6349 11.9328 16.0691C11.7778 16.6504 11.8582 17.2689 12.1564 17.789C12.4545 18.3091 12.946 18.6883 13.5229 18.8432ZM23.319 21.4549C23.7498 21.5731 24.2063 21.5598 24.6305 21.4167C25.0547 21.2736 25.4275 21.0072 25.7017 20.6511C25.9758 20.2951 26.139 19.8655 26.1705 19.4169C26.202 18.9683 26.1003 18.5208 25.8784 18.1313C25.6565 17.7417 25.3244 17.4277 24.9242 17.2289C24.524 17.0301 24.0737 16.9556 23.6305 17.0148C23.1872 17.074 22.771 17.2643 22.4345 17.5614C22.0981 17.8586 21.8566 18.2492 21.7407 18.6839C21.5852 19.2631 21.6639 19.88 21.9598 20.3993C22.2556 20.9187 22.7444 21.2983 23.319 21.4549ZM18.9577 24.5649C19.66 24.2315 20.2395 23.6825 20.6125 22.9971C20.6296 22.9556 20.6371 22.9108 20.6345 22.866C20.6319 22.8212 20.6192 22.7777 20.5974 22.7386C20.5756 22.6995 20.5453 22.6659 20.5087 22.6404C20.4721 22.6149 20.4301 22.5981 20.3861 22.5913L15.5058 21.2902C15.4641 21.2735 15.419 21.2666 15.3742 21.27C15.3293 21.2735 15.2858 21.2873 15.2469 21.3103C15.2081 21.3333 15.175 21.3649 15.1501 21.4027C15.1252 21.4405 15.1093 21.4835 15.1035 21.5284C15.082 22.3053 15.3057 23.0682 15.7424 23.7077C16.0719 24.2555 16.5777 24.6732 17.1761 24.8918C17.7889 24.985 18.4158 24.87 18.9577 24.5649Z"
fill="#E4E4E7"
/>
</g>
<defs>
<clipPath id="clip0_1104_153343">
<rect
width="31.1844"
height="27.5361"
fill="white"
transform="translate(7.47852 0.683594) rotate(14.9278)"
/>
</clipPath>
</defs>
</svg>
</div>
<div class="icon-token dart">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
<g clip-path="url(#clip0_1104_153358)">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M20.9985 5.63951L19.3197 5.79206C19.285 5.79583 19.2501 5.79934 19.215 5.80253L6.45864 6.96193L25.61 23.4441L29.8944 23.0547L28.8868 11.9688L21.6679 5.97496C21.4371 5.77538 21.222 5.67871 20.9985 5.63951ZM19.8362 4.5711C19.8886 4.56274 19.9423 4.55433 19.9968 4.54619L17.061 2.03649C16.8824 1.93075 16.5988 1.80884 16.2696 1.7194C15.9196 1.62432 15.562 1.57796 15.2659 1.60486C14.6447 1.66132 14.0986 1.80854 13.7958 1.97934L7.48343 5.72987L19.1123 4.67294C19.3199 4.65408 19.5195 4.62198 19.7354 4.58726L19.8362 4.5711ZM24.8835 24.3105L5.7343 7.86175L7.12762 23.192L13.9827 29.4351L25.2562 28.4105L24.8835 24.3105ZM1.84516 16.6203C1.75727 16.963 1.67317 17.4799 1.69812 17.7545C1.75352 18.364 2.16162 18.8963 2.66449 19.4583L5.89396 22.1496L4.70182 9.0329L1.84516 16.6203Z"
fill="#E4E4E7"
/>
</g>
<defs>
<clipPath id="clip0_1104_153358">
<rect
width="28.8"
height="28.8"
fill="white"
transform="translate(0.355469 2.96509) rotate(-5.19316)"
/>
</clipPath>
</defs>
</svg>
<div class="circles">
<div class="circle" />
<div class="circle" />
<div class="circle" />
</div>
</div>
<div class="icon-token bun">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 38 36" fill="none">
<g clip-path="url(#clip0_1104_153343)">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M15.639 30.5992C7.66287 28.4727 2.58822 21.4443 4.32475 14.9307C5.37274 10.9998 8.73409 7.96763 13.3118 6.83447C14.517 6.54291 15.5859 6.21151 16.5453 5.91402L16.8275 5.82658C17.3952 5.64952 17.9307 5.48493 18.4455 5.33587C20.0173 4.87915 21.32 4.64122 22.4771 4.9497C23.6342 5.25817 24.5189 5.99929 25.5807 7.09916C25.9067 7.42605 26.2274 7.7726 26.5688 8.14992L26.5854 8.16778C27.3802 9.02477 28.2776 9.99228 29.4877 11.147C32.8938 14.4086 34.3007 18.7077 33.2516 22.6426C31.5151 29.1562 23.6151 32.7256 15.639 30.5992ZM19.6352 8.58013C20.248 7.82555 20.6921 6.94739 20.9373 6.00561C20.9808 5.84234 21.2269 5.85676 21.2107 6.04439C21.1303 9.39681 18.9146 10.4781 17.4428 10.6445C17.2856 10.6623 17.2495 10.4479 17.3868 10.3779C18.2556 9.94792 19.0225 9.3347 19.6352 8.58013ZM22.0399 9.09713C22.1768 8.14195 22.1069 7.16899 21.835 6.24495L21.8392 6.22902C21.7973 6.06855 22.0177 5.95671 22.1048 6.09082C23.73 9.08328 22.3843 11.096 21.2209 11.9802C21.0952 12.0704 20.957 11.9055 21.0417 11.7788C21.5624 10.9671 21.903 10.0523 22.0399 9.09713ZM24.2583 9.00953C24.0063 8.07707 23.5584 7.2105 22.9446 6.46825L22.9488 6.45232C22.8438 6.32196 23.004 6.13433 23.1452 6.24022C25.8109 8.26888 25.3849 10.6932 24.6505 11.986C24.6345 12.017 24.6073 12.0408 24.5745 12.0523C24.5417 12.0637 24.5057 12.0621 24.4742 12.0476C24.4426 12.0332 24.4178 12.0071 24.405 11.9747C24.3921 11.9423 24.3922 11.9061 24.4051 11.8736C24.5603 10.9186 24.5102 9.94199 24.2583 9.00953ZM17.3486 7.96852C16.4706 8.39584 15.5135 8.63263 14.5398 8.66348C14.3858 8.66933 14.3256 8.87933 14.4769 8.91542C15.8773 9.38259 18.3444 9.32803 19.878 6.32461C19.956 6.17481 19.7455 6.05896 19.636 6.18334C19.0061 6.93294 18.2267 7.5412 17.3486 7.96852ZM13.5229 18.8432C13.9539 18.959 14.4097 18.9434 14.8327 18.7984C15.2558 18.6535 15.627 18.3857 15.8994 18.0289C16.1718 17.6722 16.3332 17.2425 16.3631 16.7943C16.393 16.3461 16.2901 15.8995 16.0674 15.5111C15.8447 15.1226 15.5123 14.8097 15.1121 14.612C14.712 14.4143 14.2621 14.3406 13.8194 14.4004C13.3768 14.4601 12.9612 14.6506 12.6254 14.9476C12.2896 15.2447 12.0485 15.6349 11.9328 16.0691C11.7778 16.6504 11.8582 17.2689 12.1564 17.789C12.4545 18.3091 12.946 18.6883 13.5229 18.8432ZM23.319 21.4549C23.7498 21.5731 24.2063 21.5598 24.6305 21.4167C25.0547 21.2736 25.4275 21.0072 25.7017 20.6511C25.9758 20.2951 26.139 19.8655 26.1705 19.4169C26.202 18.9683 26.1003 18.5208 25.8784 18.1313C25.6565 17.7417 25.3244 17.4277 24.9242 17.2289C24.524 17.0301 24.0737 16.9556 23.6305 17.0148C23.1872 17.074 22.771 17.2643 22.4345 17.5614C22.0981 17.8586 21.8566 18.2492 21.7407 18.6839C21.5852 19.2631 21.6639 19.88 21.9598 20.3993C22.2556 20.9187 22.7444 21.2983 23.319 21.4549ZM18.9577 24.5649C19.66 24.2315 20.2395 23.6825 20.6125 22.9971C20.6296 22.9556 20.6371 22.9108 20.6345 22.866C20.6319 22.8212 20.6192 22.7777 20.5974 22.7386C20.5756 22.6995 20.5453 22.6659 20.5087 22.6404C20.4721 22.6149 20.4301 22.5981 20.3861 22.5913L15.5058 21.2902C15.4641 21.2735 15.419 21.2666 15.3742 21.27C15.3293 21.2735 15.2858 21.2873 15.2469 21.3103C15.2081 21.3333 15.175 21.3649 15.1501 21.4027C15.1252 21.4405 15.1093 21.4835 15.1035 21.5284C15.082 22.3053 15.3057 23.0682 15.7424 23.7077C16.0719 24.2555 16.5777 24.6732 17.1761 24.8918C17.7889 24.985 18.4158 24.87 18.9577 24.5649Z"
fill="#E4E4E7"
/>
</g>
<defs>
<clipPath id="clip0_1104_153343">
<rect
width="31.1844"
height="27.5361"
fill="white"
transform="translate(7.47852 0.683594) rotate(14.9278)"
/>
</clipPath>
</defs>
</svg>
</div>
<div class="icon-token dart">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
<g clip-path="url(#clip0_1104_153358)">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M20.9985 5.63951L19.3197 5.79206C19.285 5.79583 19.2501 5.79934 19.215 5.80253L6.45864 6.96193L25.61 23.4441L29.8944 23.0547L28.8868 11.9688L21.6679 5.97496C21.4371 5.77538 21.222 5.67871 20.9985 5.63951ZM19.8362 4.5711C19.8886 4.56274 19.9423 4.55433 19.9968 4.54619L17.061 2.03649C16.8824 1.93075 16.5988 1.80884 16.2696 1.7194C15.9196 1.62432 15.562 1.57796 15.2659 1.60486C14.6447 1.66132 14.0986 1.80854 13.7958 1.97934L7.48343 5.72987L19.1123 4.67294C19.3199 4.65408 19.5195 4.62198 19.7354 4.58726L19.8362 4.5711ZM24.8835 24.3105L5.7343 7.86175L7.12762 23.192L13.9827 29.4351L25.2562 28.4105L24.8835 24.3105ZM1.84516 16.6203C1.75727 16.963 1.67317 17.4799 1.69812 17.7545C1.75352 18.364 2.16162 18.8963 2.66449 19.4583L5.89396 22.1496L4.70182 9.0329L1.84516 16.6203Z"
fill="#E4E4E7"
/>
</g>
<defs>
<clipPath id="clip0_1104_153358">
<rect
width="28.8"
height="28.8"
fill="white"
transform="translate(0.355469 2.96509) rotate(-5.19316)"
/>
</clipPath>
</defs>
</svg>
</div>
</div>
<style lang="scss">
@use '$scss/abstract/mixins/border-gradient' as gradients;
@use "$scss/abstract/mixins/border-gradient" as gradients;
.frame {
position: relative;
.frame {
position: relative;
}
.component {
@include gradients.border-gradient;
--m-border-radius: 17.36px;
--m-border-gradient-before: linear-gradient(
180deg,
rgba(255, 255, 255, 0.14) 0%,
rgba(255, 255, 255, 0) 106.54%
);
width: 205px;
height: 240px;
left: 0;
background: linear-gradient(
180deg,
rgba(34.63, 34.63, 36.77, 0.4) 0%,
rgba(34.63, 34.63, 36.77, 0.24) 100%
);
overflow: hidden;
box-shadow: 0px 2.8px 5.6px #00000005;
backdrop-filter: blur(27.78px) brightness(100%);
-webkit-backdrop-filter: blur(27.78px) brightness(100%);
}
.overlap-group {
position: absolute;
width: 191px;
height: 198px;
top: 35px;
left: 7px;
border-radius: 13.89px;
box-shadow: 0px 3.91px 7.82px #00000005;
backdrop-filter: blur(46.77px) brightness(100%);
-webkit-backdrop-filter: blur(46.77px) brightness(100%);
background: linear-gradient(
180deg,
rgba(255, 255, 255, 0.08) 0%,
rgba(255, 255, 255, 0) 100%
);
}
.rows {
display: inline-flex;
flex-direction: column;
align-items: flex-start;
gap: 10px;
position: relative;
top: 7px;
left: 7px;
}
.rectangle-wrapper {
position: absolute;
width: 19px;
height: 19px;
top: 9px;
left: 10px;
}
.rectangle {
position: relative;
width: 14px;
height: 14px;
top: 3px;
left: 2px;
background-color: #ffffff;
border-radius: 3.47px;
transform: rotate(45deg);
}
.div {
position: absolute;
width: 117px;
height: 1px;
top: 19px;
left: 36px;
border-radius: 171.89px;
background: linear-gradient(
180deg,
rgba(255, 255, 255, 0.8) 0%,
rgba(255, 255, 255, 0) 100%
);
opacity: 0.8;
}
.item {
opacity: 0;
position: relative;
width: 177.1px;
height: 38.2px;
background-color: #ffffff14;
border-radius: 10.42px;
box-shadow: 0px 3.91px 7.82px #00000005;
backdrop-filter: blur(46.77px) brightness(100%);
-webkit-backdrop-filter: blur(46.77px) brightness(100%);
&.is-blue {
position: absolute;
z-index: 1000;
width: 177.1px;
height: 38.2px;
border-radius: 10.42px;
box-shadow: 0px 3.91px 7.82px #00000005;
backdrop-filter: blur(46.77px) brightness(100%);
-webkit-backdrop-filter: blur(46.77px) brightness(100%);
background: linear-gradient(
180deg,
rgb(104, 163, 254) 0%,
rgb(195, 218, 255) 100%
);
}
}
.rectangle-2 {
position: relative;
width: 14px;
height: 14px;
top: 3px;
left: 2px;
border-radius: 3.47px;
transform: rotate(45deg);
background: linear-gradient(
180deg,
rgb(252.88, 53.74, 110.19) 0%,
rgb(253.27, 86.98, 107.68) 100%
);
}
.circles {
display: inline-flex;
align-items: flex-start;
gap: 5px;
position: absolute;
top: 14px;
left: 14px;
}
.circle {
position: relative;
width: 8.68px;
height: 8.68px;
background-color: #ededf0;
border-radius: 4.34px;
}
.icon-token {
display: grid;
place-items: center;
position: absolute;
background: linear-gradient(
226deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0.04) 60.84%
);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 100%;
backdrop-filter: blur(7.9449849128723145px);
width: 72px;
height: 72px;
opacity: 0;
&.bun {
top: -16px;
right: -30px;
transform: rotate(14.928deg);
}
.component {
@include gradients.border-gradient;
--m-border-radius: 17.36px;
--m-border-gradient-before: linear-gradient(
180deg,
rgba(255, 255, 255, 0.14) 0%,
rgba(255, 255, 255, 0) 106.54%
);
width: 205px;
height: 240px;
left: 0;
background: linear-gradient(
180deg,
rgba(34.63, 34.63, 36.77, 0.4) 0%,
rgba(34.63, 34.63, 36.77, 0.24) 100%
);
overflow: hidden;
box-shadow: 0px 2.8px 5.6px #00000005;
backdrop-filter: blur(27.78px) brightness(100%);
-webkit-backdrop-filter: blur(27.78px) brightness(100%);
&.dart {
top: -33px;
right: 47px;
transform: rotate(-5.193deg);
}
.overlap-group {
position: absolute;
width: 191px;
height: 198px;
top: 35px;
left: 7px;
border-radius: 13.89px;
box-shadow: 0px 3.91px 7.82px #00000005;
backdrop-filter: blur(46.77px) brightness(100%);
-webkit-backdrop-filter: blur(46.77px) brightness(100%);
background: linear-gradient(
180deg,
rgba(255, 255, 255, 0.08) 0%,
rgba(255, 255, 255, 0) 100%
);
}
.rows {
display: inline-flex;
flex-direction: column;
align-items: flex-start;
gap: 10px;
position: relative;
top: 7px;
left: 7px;
}
.rectangle-wrapper {
position: absolute;
width: 19px;
height: 19px;
top: 9px;
left: 10px;
}
.rectangle {
position: relative;
width: 14px;
height: 14px;
top: 3px;
left: 2px;
background-color: #ffffff;
border-radius: 3.47px;
transform: rotate(45deg);
}
.div {
position: absolute;
width: 117px;
height: 1px;
top: 19px;
left: 36px;
border-radius: 171.89px;
background: linear-gradient(
180deg,
rgba(255, 255, 255, 0.8) 0%,
rgba(255, 255, 255, 0) 100%
);
opacity: 0.8;
}
.item {
opacity: 0;
position: relative;
width: 177.1px;
height: 38.2px;
background-color: #ffffff14;
border-radius: 10.42px;
box-shadow: 0px 3.91px 7.82px #00000005;
backdrop-filter: blur(46.77px) brightness(100%);
-webkit-backdrop-filter: blur(46.77px) brightness(100%);
&.is-blue {
position: absolute;
z-index: 1000;
width: 177.1px;
height: 38.2px;
border-radius: 10.42px;
box-shadow: 0px 3.91px 7.82px #00000005;
backdrop-filter: blur(46.77px) brightness(100%);
-webkit-backdrop-filter: blur(46.77px) brightness(100%);
background: linear-gradient(180deg, rgb(104, 163, 254) 0%, rgb(195, 218, 255) 100%);
}
}
.rectangle-2 {
position: relative;
width: 14px;
height: 14px;
top: 3px;
left: 2px;
border-radius: 3.47px;
transform: rotate(45deg);
background: linear-gradient(
180deg,
rgb(252.88, 53.74, 110.19) 0%,
rgb(253.27, 86.98, 107.68) 100%
);
}
.circles {
display: inline-flex;
align-items: flex-start;
gap: 5px;
position: absolute;
top: 14px;
left: 14px;
}
.circle {
position: relative;
width: 8.68px;
height: 8.68px;
background-color: #ededf0;
border-radius: 4.34px;
}
.icon-token {
display: grid;
place-items: center;
position: absolute;
background: linear-gradient(
226deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0.04) 60.84%
);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 100%;
backdrop-filter: blur(7.9449849128723145px);
width: 72px;
height: 72px;
opacity: 0;
&.bun {
top: -16px;
right: -30px;
transform: rotate(14.928deg);
}
&.dart {
top: -33px;
right: 47px;
transform: rotate(-5.193deg);
}
svg {
width: 50px;
}
svg {
width: 50px;
}
}
</style>

View File

@@ -1,70 +1,76 @@
<script lang="ts">
import { onMount } from 'svelte';
import { onMount } from "svelte";
let toShow = 0;
let showCaret = false;
let toShow = 0;
let showCaret = false;
onMount(() => {
setTimeout(() => {
toShow = 1;
}, 250);
setTimeout(() => {
toShow = 2;
}, 500);
setTimeout(() => {
toShow = 3;
}, 750);
setTimeout(() => {
toShow = 4;
}, 1000);
onMount(() => {
setTimeout(() => {
toShow = 1;
}, 250);
setTimeout(() => {
toShow = 2;
}, 500);
setTimeout(() => {
toShow = 3;
}, 750);
setTimeout(() => {
toShow = 4;
}, 1000);
setTimeout(() => {
showCaret = true;
}, 1500);
setTimeout(() => {
showCaret = true;
}, 1500);
setTimeout(() => {
showCaret = false;
}, 2000);
setTimeout(() => {
showCaret = false;
}, 2000);
setTimeout(() => {
showCaret = true;
}, 2500);
setTimeout(() => {
showCaret = true;
}, 2500);
setTimeout(() => {
showCaret = false;
}, 3000);
setTimeout(() => {
showCaret = true;
}, 3000);
});
setTimeout(() => {
showCaret = false;
}, 3000);
setTimeout(() => {
showCaret = true;
}, 3000);
});
</script>
<svg xmlns="http://www.w3.org/2000/svg" width="224" height="96" viewBox="0 0 224 96" fill="none">
{#if showCaret}
<path d="M169.521 96V84.8145H223.6V96H169.521Z" fill="#FD366E" />
{/if}
{#if toShow >= 4}
<path
d="M152.912 81.6652C141.874 81.6652 134.623 76.6697 134.623 64.6154V36.0543H124.775V24.7602H135.381V8.79638H147.501V24.7602H163.517V36.0543H147.501V64.5068C147.501 68.5249 149.124 70.2624 153.02 70.2624H162.868V81.6652H152.912Z"
fill="white"
/>
{/if}
{#if toShow >= 3}
<path
d="M109.647 15.9638C104.993 15.9638 101.53 12.4887 101.53 7.9276C101.53 3.47511 104.993 0 109.647 0C114.3 0 117.763 3.47511 117.763 7.9276C117.763 12.4887 114.3 15.9638 109.647 15.9638ZM103.154 81.6652V36.0543H93.1975V24.7602H115.923V81.6652H103.154Z"
fill="white"
/>
{/if}
{#if toShow >= 2}
<path
d="M36.3068 81.6652V24.7602H49.0766V31.276H50.0506C52.5396 26.9321 57.734 23.3484 65.3093 23.3484C77.7544 23.3484 85.6543 32.6878 85.6543 44.4163V81.6652H72.8846V47.457C72.8846 40.3982 67.9066 35.5113 61.4135 35.5113C54.3793 35.5113 49.0766 40.9412 49.0766 48.1086V81.6652H36.3068Z"
fill="white"
/>
{/if}
{#if toShow >= 1}
<path
d="M16.8496 15.9638C12.1962 15.9638 8.73319 12.4887 8.73319 7.9276C8.73319 3.47511 12.1962 0 16.8496 0C21.5029 0 24.9659 3.47511 24.9659 7.9276C24.9659 12.4887 21.5029 15.9638 16.8496 15.9638ZM10.3565 81.6652V36.0543H0.400391V24.7602H23.1262V81.6652H10.3565Z"
fill="white"
/>
{/if}
<svg
xmlns="http://www.w3.org/2000/svg"
width="224"
height="96"
viewBox="0 0 224 96"
fill="none"
>
{#if showCaret}
<path d="M169.521 96V84.8145H223.6V96H169.521Z" fill="#FD366E" />
{/if}
{#if toShow >= 4}
<path
d="M152.912 81.6652C141.874 81.6652 134.623 76.6697 134.623 64.6154V36.0543H124.775V24.7602H135.381V8.79638H147.501V24.7602H163.517V36.0543H147.501V64.5068C147.501 68.5249 149.124 70.2624 153.02 70.2624H162.868V81.6652H152.912Z"
fill="white"
/>
{/if}
{#if toShow >= 3}
<path
d="M109.647 15.9638C104.993 15.9638 101.53 12.4887 101.53 7.9276C101.53 3.47511 104.993 0 109.647 0C114.3 0 117.763 3.47511 117.763 7.9276C117.763 12.4887 114.3 15.9638 109.647 15.9638ZM103.154 81.6652V36.0543H93.1975V24.7602H115.923V81.6652H103.154Z"
fill="white"
/>
{/if}
{#if toShow >= 2}
<path
d="M36.3068 81.6652V24.7602H49.0766V31.276H50.0506C52.5396 26.9321 57.734 23.3484 65.3093 23.3484C77.7544 23.3484 85.6543 32.6878 85.6543 44.4163V81.6652H72.8846V47.457C72.8846 40.3982 67.9066 35.5113 61.4135 35.5113C54.3793 35.5113 49.0766 40.9412 49.0766 48.1086V81.6652H36.3068Z"
fill="white"
/>
{/if}
{#if toShow >= 1}
<path
d="M16.8496 15.9638C12.1962 15.9638 8.73319 12.4887 8.73319 7.9276C8.73319 3.47511 12.1962 0 16.8496 0C21.5029 0 24.9659 3.47511 24.9659 7.9276C24.9659 12.4887 21.5029 15.9638 16.8496 15.9638ZM10.3565 81.6652V36.0543H0.400391V24.7602H23.1262V81.6652H10.3565Z"
fill="white"
/>
{/if}
</svg>

View File

@@ -1,176 +1,176 @@
<script lang="ts">
import { animate, inView, spring } from 'motion';
import { onMount } from 'svelte';
import { animate, inView, spring } from "motion";
import { onMount } from "svelte";
export let delay = 1;
export let delay = 1;
let messaging1: HTMLElement;
let messaging2: HTMLElement;
let dot: HTMLElement;
let messaging1: HTMLElement;
let messaging2: HTMLElement;
let dot: HTMLElement;
onMount(() => {
inView(messaging1, () => {
animate(
messaging1,
{
scale: 0.92,
opacity: 0.48,
y: 16
},
{
delay: 0.15 + delay,
easing: spring({ mass: 1, stiffness: 711.1, damping: 40 })
}
);
onMount(() => {
inView(messaging1, () => {
animate(
messaging1,
{
scale: 0.92,
opacity: 0.48,
y: 16,
},
{
delay: 0.15 + delay,
easing: spring({ mass: 1, stiffness: 711.1, damping: 40 }),
},
);
animate(
messaging2,
{
opacity: 1,
y: [-10, 0]
},
{
delay: 0.2 + delay,
easing: spring({ mass: 1, stiffness: 711.1, damping: 40 })
}
);
animate(
messaging2,
{
opacity: 1,
y: [-10, 0],
},
{
delay: 0.2 + delay,
easing: spring({ mass: 1, stiffness: 711.1, damping: 40 }),
},
);
animate(
dot,
{
scale: [0, 1]
},
{
delay: 0.5 + delay,
easing: spring({ mass: 1, stiffness: 711.1, damping: 40 })
}
);
});
animate(
dot,
{
scale: [0, 1],
},
{
delay: 0.5 + delay,
easing: spring({ mass: 1, stiffness: 711.1, damping: 40 }),
},
);
});
});
</script>
<div class="wrapper">
<div class="container messaging-1" bind:this={messaging1}>
<div class="box1" />
<div class="box2" />
<div class="box3" />
<div class="circle">
<div class="circle-inner" />
</div>
<div class="container messaging-1" bind:this={messaging1}>
<div class="box1" />
<div class="box2" />
<div class="box3" />
<div class="circle">
<div class="circle-inner" />
</div>
</div>
<div class="container messaging-2" bind:this={messaging2}>
<div class="box1" />
<div class="box2" />
<div class="box3" />
<div class="circle">
<div class="circle-inner" />
<svg
xmlns="http://www.w3.org/2000/svg"
width="40"
height="40"
viewBox="0 0 40 40"
fill="none"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M31 6.76172C32.2351 6.76172 33.2363 7.76297 33.2363 8.99807V32.9981H28.7636V14.3971L8.58131 34.5794L5.41864 31.4167L25.601 11.2344H6.99998V6.76172H31Z"
fill="#E4E4E7"
/>
</svg>
<div class="dot" bind:this={dot} />
</div>
<div class="container messaging-2" bind:this={messaging2}>
<div class="box1" />
<div class="box2" />
<div class="box3" />
<div class="circle">
<div class="circle-inner" />
<svg
xmlns="http://www.w3.org/2000/svg"
width="40"
height="40"
viewBox="0 0 40 40"
fill="none"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M31 6.76172C32.2351 6.76172 33.2363 7.76297 33.2363 8.99807V32.9981H28.7636V14.3971L8.58131 34.5794L5.41864 31.4167L25.601 11.2344H6.99998V6.76172H31Z"
fill="#E4E4E7"
/>
</svg>
<div class="dot" bind:this={dot} />
</div>
</div>
</div>
<style lang="scss">
.wrapper {
width: 306px;
height: 90px;
position: relative;
/* background-color: rgba(255, 0, 0, 0.1); */
.wrapper {
width: 306px;
height: 90px;
position: relative;
/* background-color: rgba(255, 0, 0, 0.1); */
}
.messaging-2 {
opacity: 0;
backdrop-filter: blur(11.03px);
}
.container {
width: 306px;
height: 63px;
position: absolute;
}
.box1 {
width: 306px;
height: 60px;
left: 0;
top: 3px;
position: absolute;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
}
.box2 {
width: 166px;
height: 16px;
left: 72px;
top: 7px;
position: absolute;
background: rgba(255, 255, 255, 0.1);
border-radius: 999px;
}
.box3 {
width: 120px;
height: 16px;
left: 72px;
top: 27px;
position: absolute;
background: rgba(255, 255, 255, 0.1);
border-radius: 999px;
}
.circle {
width: 52px;
height: 52px;
left: 4px;
top: 7px;
position: absolute;
display: grid;
place-items: center;
.dot {
width: 20px;
height: 20px;
background: linear-gradient(111deg, #fd366e 0%, #fe9567 144.87%);
border-radius: 100%;
filter: drop-shadow(0px 0.634px 1.269px rgba(0, 0, 0, 0.02));
backdrop-filter: blur(1.982085108757019px);
position: absolute;
top: -9px;
right: -10px;
transform: scale(0);
}
}
.messaging-2 {
opacity: 0;
backdrop-filter: blur(11.03px);
}
.container {
width: 306px;
height: 63px;
position: absolute;
}
.box1 {
width: 306px;
height: 60px;
left: 0;
top: 3px;
position: absolute;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
}
.box2 {
width: 166px;
height: 16px;
left: 72px;
top: 7px;
position: absolute;
background: rgba(255, 255, 255, 0.1);
border-radius: 999px;
}
.box3 {
width: 120px;
height: 16px;
left: 72px;
top: 27px;
position: absolute;
background: rgba(255, 255, 255, 0.1);
border-radius: 999px;
}
.circle {
width: 52px;
height: 52px;
left: 4px;
top: 7px;
position: absolute;
display: grid;
place-items: center;
.dot {
width: 20px;
height: 20px;
background: linear-gradient(111deg, #fd366e 0%, #fe9567 144.87%);
border-radius: 100%;
filter: drop-shadow(0px 0.634px 1.269px rgba(0, 0, 0, 0.02));
backdrop-filter: blur(1.982085108757019px);
position: absolute;
top: -9px;
right: -10px;
transform: scale(0);
}
}
.circle-inner {
width: 52px;
height: 52px;
left: 0;
top: 0;
position: absolute;
background: linear-gradient(
218deg,
rgba(255, 255, 255, 0.2) 0%,
rgba(255, 255, 255, 0) 100%
);
border-radius: 8px;
/* backdrop-filter: blur(11.03px); */
}
.circle-inner {
width: 52px;
height: 52px;
left: 0;
top: 0;
position: absolute;
background: linear-gradient(
218deg,
rgba(255, 255, 255, 0.2) 0%,
rgba(255, 255, 255, 0) 100%
);
border-radius: 8px;
/* backdrop-filter: blur(11.03px); */
}
</style>

View File

@@ -1,220 +1,224 @@
<script lang="ts">
import { animate, inView, spring } from 'motion';
import { onMount } from 'svelte';
import { animate, inView, spring } from "motion";
import { onMount } from "svelte";
export let delay = 1;
const id = 'operators-anim';
export let delay = 1;
const id = "operators-anim";
onMount(() => {
inView(`#${id}`, () => {
animate(
`#${id} .filter`,
{
scale: [1, 0.9, 1]
},
{
delay: delay,
duration: 0.2,
easing: 'ease-out'
}
);
onMount(() => {
inView(`#${id}`, () => {
animate(
`#${id} .filter`,
{
scale: [1, 0.9, 1],
},
{
delay: delay,
duration: 0.2,
easing: "ease-out",
},
);
animate(
`#${id} .operators`,
{
y: [-10, 0],
animate(
`#${id} .operators`,
{
y: [-10, 0],
opacity: [0, 1]
},
{
delay: delay + 0.2,
easing: spring({ mass: 1, stiffness: 177, damping: 20 })
}
);
});
opacity: [0, 1],
},
{
delay: delay + 0.2,
easing: spring({ mass: 1, stiffness: 177, damping: 20 }),
},
);
});
});
</script>
<div class="component" {id}>
<div class="overlap-wrapper">
<div class="overlap">
<div class="rectangle">
<div class="icon">
<svg
xmlns="http://www.w3.org/2000/svg"
width="29"
height="31"
viewBox="0 0 29 31"
fill="none"
>
<circle
cx="14.0031"
cy="14.1464"
r="12.7772"
stroke="#D9D9D9"
stroke-width="2.03631"
/>
<path
d="M22.2791 24.3532L27.7406 29.8143"
stroke="#D9D9D9"
stroke-width="2.03631"
/>
</svg>
</div>
<div class="diamond" />
<div class="filter">
<svg
xmlns="http://www.w3.org/2000/svg"
width="35"
height="16"
viewBox="0 0 35 16"
fill="none"
>
<path
d="M9.87436 7.70947L1.49936 7.70947M5.68686 3.52197V11.897M18.4085 0.729004H33.7627L27.4814 7.70817V12.5936L24.6898 15.3853V7.70817L18.4085 0.729004Z"
stroke="#E4E4E7"
stroke-width="1.11667"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
</div>
<div class="operators">
<span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="23"
viewBox="0 0 24 23"
fill="none"
>
<path
d="M21.5085 16.0575H22.3628V17.3138H21.274C20.5705 17.3138 20.068 17.1295 19.6995 16.6605L19.2138 16.024C18.4098 16.9285 17.455 17.4143 16.383 17.4143C14.4568 17.4143 13.1335 16.2753 13.1335 14.3658C13.1335 13.009 13.904 11.7695 15.378 11.0158C14.574 9.89353 14.3228 9.24028 14.3228 8.30228C14.3228 6.67753 15.4953 5.48828 17.2038 5.48828C18.728 5.48828 19.8838 6.56028 19.8838 8.06778C19.8838 9.35753 19.0463 10.4798 17.3545 11.401L19.2808 13.88L20.8888 10.9823H22.3125L20.0848 14.9018L20.5705 15.5383C20.872 15.9235 21.1233 16.0575 21.5085 16.0575ZM17.1535 6.69428C16.2323 6.69428 15.6963 7.29728 15.6963 8.21853C15.6963 9.07278 15.9978 9.62553 16.6343 10.463C17.8905 9.87678 18.5103 9.05603 18.5103 8.10128C18.5103 7.21353 17.9575 6.69428 17.1535 6.69428ZM16.4333 16.158C17.2038 16.158 17.924 15.7728 18.46 15.0525L16.0983 11.9873L16.048 11.937C14.976 12.5233 14.5405 13.2268 14.5405 14.2485C14.5405 15.4713 15.2608 16.158 16.4333 16.158Z"
fill="#ADADB0"
/>
<path
d="M10.5 16.0575H11.3542V17.3138H10.2655C9.562 17.3138 9.0595 17.1295 8.691 16.6605L8.20525 16.024C7.40125 16.9285 6.4465 17.4143 5.3745 17.4143C3.44825 17.4143 2.125 16.2753 2.125 14.3658C2.125 13.009 2.8955 11.7695 4.3695 11.0158C3.5655 9.89353 3.31425 9.24028 3.31425 8.30228C3.31425 6.67753 4.48675 5.48828 6.19525 5.48828C7.7195 5.48828 8.87525 6.56028 8.87525 8.06778C8.87525 9.35753 8.03775 10.4798 6.346 11.401L8.27225 13.88L9.88025 10.9823H11.304L9.07625 14.9018L9.562 15.5383C9.8635 15.9235 10.1148 16.0575 10.5 16.0575ZM6.145 6.69428C5.22375 6.69428 4.68775 7.29728 4.68775 8.21853C4.68775 9.07278 4.98925 9.62553 5.62575 10.463C6.882 9.87678 7.50175 9.05603 7.50175 8.10128C7.50175 7.21353 6.949 6.69428 6.145 6.69428ZM5.42475 16.158C6.19525 16.158 6.9155 15.7728 7.4515 15.0525L5.08975 11.9873L5.0395 11.937C3.9675 12.5233 3.532 13.2268 3.532 14.2485C3.532 15.4713 4.25225 16.158 5.42475 16.158Z"
fill="#ADADB0"
/>
</svg>
</span>
<span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M7.70834 4.38672V19.7409"
stroke="#ADADB0"
stroke-width="1.26129"
stroke-linejoin="round"
/>
<path
d="M16.0833 4.38672V19.7409"
stroke="#ADADB0"
stroke-width="1.26129"
stroke-linejoin="round"
/>
</svg>
</span>
</div>
<div class="overlap-wrapper">
<div class="overlap">
<div class="rectangle">
<div class="icon">
<svg
xmlns="http://www.w3.org/2000/svg"
width="29"
height="31"
viewBox="0 0 29 31"
fill="none"
>
<circle
cx="14.0031"
cy="14.1464"
r="12.7772"
stroke="#D9D9D9"
stroke-width="2.03631"
/>
<path
d="M22.2791 24.3532L27.7406 29.8143"
stroke="#D9D9D9"
stroke-width="2.03631"
/>
</svg>
</div>
<div class="diamond" />
<div class="filter">
<svg
xmlns="http://www.w3.org/2000/svg"
width="35"
height="16"
viewBox="0 0 35 16"
fill="none"
>
<path
d="M9.87436 7.70947L1.49936 7.70947M5.68686 3.52197V11.897M18.4085 0.729004H33.7627L27.4814 7.70817V12.5936L24.6898 15.3853V7.70817L18.4085 0.729004Z"
stroke="#E4E4E7"
stroke-width="1.11667"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
</div>
<div class="operators">
<span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="23"
viewBox="0 0 24 23"
fill="none"
>
<path
d="M21.5085 16.0575H22.3628V17.3138H21.274C20.5705 17.3138 20.068 17.1295 19.6995 16.6605L19.2138 16.024C18.4098 16.9285 17.455 17.4143 16.383 17.4143C14.4568 17.4143 13.1335 16.2753 13.1335 14.3658C13.1335 13.009 13.904 11.7695 15.378 11.0158C14.574 9.89353 14.3228 9.24028 14.3228 8.30228C14.3228 6.67753 15.4953 5.48828 17.2038 5.48828C18.728 5.48828 19.8838 6.56028 19.8838 8.06778C19.8838 9.35753 19.0463 10.4798 17.3545 11.401L19.2808 13.88L20.8888 10.9823H22.3125L20.0848 14.9018L20.5705 15.5383C20.872 15.9235 21.1233 16.0575 21.5085 16.0575ZM17.1535 6.69428C16.2323 6.69428 15.6963 7.29728 15.6963 8.21853C15.6963 9.07278 15.9978 9.62553 16.6343 10.463C17.8905 9.87678 18.5103 9.05603 18.5103 8.10128C18.5103 7.21353 17.9575 6.69428 17.1535 6.69428ZM16.4333 16.158C17.2038 16.158 17.924 15.7728 18.46 15.0525L16.0983 11.9873L16.048 11.937C14.976 12.5233 14.5405 13.2268 14.5405 14.2485C14.5405 15.4713 15.2608 16.158 16.4333 16.158Z"
fill="#ADADB0"
/>
<path
d="M10.5 16.0575H11.3542V17.3138H10.2655C9.562 17.3138 9.0595 17.1295 8.691 16.6605L8.20525 16.024C7.40125 16.9285 6.4465 17.4143 5.3745 17.4143C3.44825 17.4143 2.125 16.2753 2.125 14.3658C2.125 13.009 2.8955 11.7695 4.3695 11.0158C3.5655 9.89353 3.31425 9.24028 3.31425 8.30228C3.31425 6.67753 4.48675 5.48828 6.19525 5.48828C7.7195 5.48828 8.87525 6.56028 8.87525 8.06778C8.87525 9.35753 8.03775 10.4798 6.346 11.401L8.27225 13.88L9.88025 10.9823H11.304L9.07625 14.9018L9.562 15.5383C9.8635 15.9235 10.1148 16.0575 10.5 16.0575ZM6.145 6.69428C5.22375 6.69428 4.68775 7.29728 4.68775 8.21853C4.68775 9.07278 4.98925 9.62553 5.62575 10.463C6.882 9.87678 7.50175 9.05603 7.50175 8.10128C7.50175 7.21353 6.949 6.69428 6.145 6.69428ZM5.42475 16.158C6.19525 16.158 6.9155 15.7728 7.4515 15.0525L5.08975 11.9873L5.0395 11.937C3.9675 12.5233 3.532 13.2268 3.532 14.2485C3.532 15.4713 4.25225 16.158 5.42475 16.158Z"
fill="#ADADB0"
/>
</svg>
</span>
<span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M7.70834 4.38672V19.7409"
stroke="#ADADB0"
stroke-width="1.26129"
stroke-linejoin="round"
/>
<path
d="M16.0833 4.38672V19.7409"
stroke="#ADADB0"
stroke-width="1.26129"
stroke-linejoin="round"
/>
</svg>
</span>
</div>
</div>
</div>
</div>
<style lang="scss">
@use '$scss/abstract/mixins/border-gradient' as gradients;
@use "$scss/abstract/mixins/border-gradient" as gradients;
.component {
background-color: transparent;
.component {
background-color: transparent;
--m-border-gradient-before: linear-gradient(
to bottom,
rgba(255, 255, 255, 0.24),
rgba(255, 255, 255, 0)
);
}
.overlap {
position: relative;
width: 441px;
height: 134px;
}
.icon {
width: 39px;
height: 39px;
display: grid;
place-items: center;
}
.rectangle {
@include gradients.border-gradient;
--m-border-radius: 11.17px;
width: 441px;
height: 61px;
background-color: #ffffff0a;
box-shadow: 0px 2.25px 4.5px #00000005;
backdrop-filter: blur(22.33px) brightness(100%);
-webkit-backdrop-filter: blur(22.33px) brightness(100%);
display: flex;
align-items: center;
padding: 11.17px;
}
.diamond {
position: relative;
width: 17px;
height: 17px;
border-radius: 4.19px;
transform: rotate(45deg);
background: linear-gradient(180deg, rgb(254, 149, 103) 0%, rgb(254, 170, 133) 100%);
margin-inline-start: 16px;
}
.filter {
width: 64px;
height: 40px;
flex-shrink: 0;
border-radius: 1394.438px;
background: linear-gradient(134deg, #fd366e 25.26%, #fe9567 157.9%);
box-shadow: 0px 1.067px 2.134px 0px rgba(0, 0, 0, 0.02);
backdrop-filter: blur(3.3342883586883545px);
margin-inline-start: 20px;
display: grid;
place-items: center;
}
.operators {
@include gradients.border-gradient;
--m-border-radius: 11.17px;
position: absolute;
left: 100px;
background: rgba(255, 255, 255, 0.04);
display: flex;
flex-direction: column;
padding: 6px;
gap: 6px;
opacity: 0;
span {
@include gradients.border-gradient;
--m-border-radius: 8px;
background: rgba(255, 255, 255, 0.04);
width: 58px;
height: 30px;
display: grid;
place-items: center;
}
--m-border-gradient-before: linear-gradient(
to bottom,
rgba(255, 255, 255, 0.24),
rgba(255, 255, 255, 0)
);
}
.overlap {
position: relative;
width: 441px;
height: 134px;
}
.icon {
width: 39px;
height: 39px;
display: grid;
place-items: center;
}
.rectangle {
@include gradients.border-gradient;
--m-border-radius: 11.17px;
width: 441px;
height: 61px;
background-color: #ffffff0a;
box-shadow: 0px 2.25px 4.5px #00000005;
backdrop-filter: blur(22.33px) brightness(100%);
-webkit-backdrop-filter: blur(22.33px) brightness(100%);
display: flex;
align-items: center;
padding: 11.17px;
}
.diamond {
position: relative;
width: 17px;
height: 17px;
border-radius: 4.19px;
transform: rotate(45deg);
background: linear-gradient(
180deg,
rgb(254, 149, 103) 0%,
rgb(254, 170, 133) 100%
);
margin-inline-start: 16px;
}
.filter {
width: 64px;
height: 40px;
flex-shrink: 0;
border-radius: 1394.438px;
background: linear-gradient(134deg, #fd366e 25.26%, #fe9567 157.9%);
box-shadow: 0px 1.067px 2.134px 0px rgba(0, 0, 0, 0.02);
backdrop-filter: blur(3.3342883586883545px);
margin-inline-start: 20px;
display: grid;
place-items: center;
}
.operators {
@include gradients.border-gradient;
--m-border-radius: 11.17px;
position: absolute;
left: 100px;
background: rgba(255, 255, 255, 0.04);
display: flex;
flex-direction: column;
padding: 6px;
gap: 6px;
opacity: 0;
span {
@include gradients.border-gradient;
--m-border-radius: 8px;
background: rgba(255, 255, 255, 0.04);
width: 58px;
height: 30px;
display: grid;
place-items: center;
}
}
</style>

View File

@@ -1,243 +1,248 @@
<script lang="ts">
import { onMount } from 'svelte';
import GridSvg from './(assets)/grid.svg';
import { animate, inView, spring } from 'motion';
import { onMount } from "svelte";
import GridSvg from "./(assets)/grid.svg";
import { animate, inView, spring } from "motion";
export let delay = 1;
let wrapper: HTMLElement;
let renderLine: HTMLElement;
let blur: HTMLElement;
export let delay = 1;
let wrapper: HTMLElement;
let renderLine: HTMLElement;
let blur: HTMLElement;
onMount(() => {
inView(wrapper, () => {
animate(
renderLine,
{
y: 100
},
{
easing: spring({ mass: 1, stiffness: 100, damping: 15 }),
delay: delay
}
);
onMount(() => {
inView(wrapper, () => {
animate(
renderLine,
{
y: 100,
},
{
easing: spring({ mass: 1, stiffness: 100, damping: 15 }),
delay: delay,
},
);
animate(
blur,
{
top: '100px' // Need to use top, otherwise blur disappears on FF
},
{
easing: spring({ mass: 1, stiffness: 100, damping: 15 }),
delay: delay
}
);
});
animate(
blur,
{
top: "100px", // Need to use top, otherwise blur disappears on FF
},
{
easing: spring({ mass: 1, stiffness: 100, damping: 15 }),
delay: delay,
},
);
});
});
</script>
<div class="wrapper" bind:this={wrapper}>
<div class="interface">
<div class="bg" />
<div class="interface">
<div class="bg" />
<div class="circles">
<div class="circle" />
<div class="circle" style="left: 16px;" />
<div class="circle" style="left: 32px;" />
</div>
<div class="screenbg-wrapper">
<div class="screenbg" style:--bg="url('{GridSvg}')">
<svg
xmlns="http://www.w3.org/2000/svg"
width="160"
viewBox="0 0 203 196"
fill="none"
>
<rect
width="104.614"
height="104.614"
transform="matrix(0.965798 0.259298 -0.965798 0.259298 101.037 0.640625)"
fill="url(#paint0_linear_397_1469)"
/>
<path
d="M202.071 168.564L101.035 195.69V54.8919L202.071 27.7656V168.564Z"
fill="url(#paint1_linear_397_1469)"
/>
<path
d="M-0.00118256 168.564L101.035 195.69V54.8919L-0.00118256 27.7656V168.564Z"
fill="url(#paint2_linear_397_1469)"
/>
<defs>
<linearGradient
id="paint0_linear_397_1469"
x1="88.7581"
y1="77.7802"
x2="-414.737"
y2="-83.3163"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#FED367" />
<stop offset="1" stop-color="#FEE5A4" />
</linearGradient>
<linearGradient
id="paint1_linear_397_1469"
x1="151.358"
y1="27.9464"
x2="168.133"
y2="106.552"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#FFEDC2" />
<stop offset="1" stop-color="#FEE5A4" />
</linearGradient>
<linearGradient
id="paint2_linear_397_1469"
x1="50.9873"
y1="-306.494"
x2="50.712"
y2="228.654"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#FFEDC2" />
<stop offset="1" stop-color="#FED367" />
</linearGradient>
</defs>
</svg>
</div>
<div class="circles">
<div class="circle" />
<div class="circle" style="left: 16px;" />
<div class="circle" style="left: 32px;" />
</div>
<div class="screenbg-wrapper">
<div class="screenbg" style:--bg="url('{GridSvg}')">
<svg
xmlns="http://www.w3.org/2000/svg"
width="160"
viewBox="0 0 203 196"
fill="none"
>
<rect
width="104.614"
height="104.614"
transform="matrix(0.965798 0.259298 -0.965798 0.259298 101.037 0.640625)"
fill="url(#paint0_linear_397_1469)"
/>
<path
d="M202.071 168.564L101.035 195.69V54.8919L202.071 27.7656V168.564Z"
fill="url(#paint1_linear_397_1469)"
/>
<path
d="M-0.00118256 168.564L101.035 195.69V54.8919L-0.00118256 27.7656V168.564Z"
fill="url(#paint2_linear_397_1469)"
/>
<defs>
<linearGradient
id="paint0_linear_397_1469"
x1="88.7581"
y1="77.7802"
x2="-414.737"
y2="-83.3163"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#FED367" />
<stop offset="1" stop-color="#FEE5A4" />
</linearGradient>
<linearGradient
id="paint1_linear_397_1469"
x1="151.358"
y1="27.9464"
x2="168.133"
y2="106.552"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#FFEDC2" />
<stop offset="1" stop-color="#FEE5A4" />
</linearGradient>
<linearGradient
id="paint2_linear_397_1469"
x1="50.9873"
y1="-306.494"
x2="50.712"
y2="228.654"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#FFEDC2" />
<stop offset="1" stop-color="#FED367" />
</linearGradient>
</defs>
</svg>
</div>
<div class="blur" bind:this={blur} />
</div>
</div>
<div class="render-line" bind:this={renderLine}>
<div class="tick" />
<div class="line" />
<div class="blur" bind:this={blur} />
</div>
</div>
<div class="render-line" bind:this={renderLine}>
<div class="tick" />
<div class="line" />
</div>
</div>
<style lang="scss">
@use '$scss/abstract/mixins/border-gradient' as gradients;
@use "$scss/abstract/mixins/border-gradient" as gradients;
.wrapper {
position: relative;
.wrapper {
position: relative;
}
.render-line {
width: 294px;
height: 10px;
position: absolute;
top: 30px;
left: -18px;
.tick {
width: 43.14px;
height: 9.76px;
left: 0px;
top: 0px;
position: absolute;
background: #fd366e;
border-radius: 12.32px;
}
.render-line {
width: 294px;
height: 10px;
.line {
width: 251px;
height: 0px;
left: 40px;
top: 4px;
position: absolute;
background: linear-gradient(
180deg,
white 0%,
rgba(255, 255, 255, 0) 100%
);
border: 1px #fd366e solid;
}
}
.interface {
width: 283px;
height: 260px;
position: relative;
overflow: hidden;
}
.bg {
width: 277px;
height: 260px;
left: 0px;
top: 0px;
position: absolute;
background: linear-gradient(
180deg,
rgba(34.63, 34.63, 36.77, 0.4) 0%,
rgba(34.63, 34.63, 36.77, 0.24) 100%
);
background-position: center;
background-repeat: no-repeat;
border-radius: 12px;
overflow: hidden;
box-shadow: 0px 2.484086751937866px 4.968173503875732px rgba(0, 0, 0, 0.02);
backdrop-filter: blur(15.53px);
-webkit-backdrop-filter: blur(15.53px);
@include gradients.border-gradient;
--m-border-radius: 12px;
--m-border-gradient-before: linear-gradient(
180deg,
rgba(255, 255, 255, 0.14) 0%,
rgba(255, 255, 255, 0) 106.54%
);
}
.circles {
width: 42px;
height: 10px;
left: 12px;
top: 12px;
position: absolute;
}
.circle {
width: 10px;
height: 10px;
left: 0px;
top: 0px;
position: absolute;
background: #ededf0;
border-radius: 9999px;
}
.screenbg-wrapper {
width: 269px;
height: 219px;
left: 4px;
top: 34px;
position: absolute;
overflow: hidden;
border-radius: 8px;
.screenbg {
inset: -6px;
position: absolute;
background: var(--bg);
background-size: cover;
background-position: center;
box-shadow: 0px 2.098677158355713px 4.197354316711426px
rgba(0, 0, 0, 0.02);
backdrop-filter: blur(25.1px);
svg {
position: absolute;
top: 30px;
left: -18px;
.tick {
width: 43.14px;
height: 9.76px;
left: 0px;
top: 0px;
position: absolute;
background: #fd366e;
border-radius: 12.32px;
}
.line {
width: 251px;
height: 0px;
left: 40px;
top: 4px;
position: absolute;
background: linear-gradient(180deg, white 0%, rgba(255, 255, 255, 0) 100%);
border: 1px #fd366e solid;
}
top: 20px;
left: 50%;
transform: translateX(-50%);
}
}
.interface {
width: 283px;
height: 260px;
position: relative;
overflow: hidden;
}
.bg {
width: 277px;
height: 260px;
left: 0px;
top: 0px;
position: absolute;
background: linear-gradient(
180deg,
rgba(34.63, 34.63, 36.77, 0.4) 0%,
rgba(34.63, 34.63, 36.77, 0.24) 100%
);
background-position: center;
background-repeat: no-repeat;
border-radius: 12px;
overflow: hidden;
box-shadow: 0px 2.484086751937866px 4.968173503875732px rgba(0, 0, 0, 0.02);
backdrop-filter: blur(15.53px);
-webkit-backdrop-filter: blur(15.53px);
@include gradients.border-gradient;
--m-border-radius: 12px;
--m-border-gradient-before: linear-gradient(
180deg,
rgba(255, 255, 255, 0.14) 0%,
rgba(255, 255, 255, 0) 106.54%
);
}
.circles {
width: 42px;
height: 10px;
left: 12px;
top: 12px;
position: absolute;
}
.circle {
width: 10px;
height: 10px;
left: 0px;
top: 0px;
position: absolute;
background: #ededf0;
border-radius: 9999px;
}
.screenbg-wrapper {
width: 269px;
height: 219px;
left: 4px;
top: 34px;
position: absolute;
overflow: hidden;
border-radius: 8px;
.screenbg {
inset: -6px;
position: absolute;
background: var(--bg);
background-size: cover;
background-position: center;
box-shadow: 0px 2.098677158355713px 4.197354316711426px rgba(0, 0, 0, 0.02);
backdrop-filter: blur(25.1px);
svg {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
}
}
.blur {
width: 269px;
height: 220px;
top: 0px;
position: absolute;
background: rgba(53, 49, 43, 0.01);
border-top-left-radius: 8px;
border-top-right-radius: 8px;
backdrop-filter: blur(21.17px);
-webkit-backdrop-filter: blur(21.17px);
}
.blur {
width: 269px;
height: 220px;
top: 0px;
position: absolute;
background: rgba(53, 49, 43, 0.01);
border-top-left-radius: 8px;
border-top-right-radius: 8px;
backdrop-filter: blur(21.17px);
-webkit-backdrop-filter: blur(21.17px);
}
}
</style>

View File

@@ -1,15 +1,15 @@
import Logo from './Logo.svelte';
import Messaging from './Messaging.svelte';
import SSR from './SSR.svelte';
import Enum from './Enum.svelte';
import Operators from './Operators.svelte';
import Integrations from './Integrations.svelte';
import Logo from "./Logo.svelte";
import Messaging from "./Messaging.svelte";
import SSR from "./SSR.svelte";
import Enum from "./Enum.svelte";
import Operators from "./Operators.svelte";
import Integrations from "./Integrations.svelte";
export const Animations = {
Logo,
Messaging,
SSR,
Enum,
Operators,
Integrations
Logo,
Messaging,
SSR,
Enum,
Operators,
Integrations,
};

View File

@@ -1,45 +1,45 @@
<script lang="ts">
import { createCountdown } from '../helpers';
import Counter from './Counter.svelte';
import { createCountdown } from "../helpers";
import Counter from "./Counter.svelte";
export let date: Date;
export let date: Date;
const { days, hours, minutes, seconds } = createCountdown(date);
const { days, hours, minutes, seconds } = createCountdown(date);
</script>
<div class="web-card is-normal web-u-color-text-primary">
<img src="/images/icons/gradients/lock.svg" alt="Lock" />
{#if $days > 1}
<p class="web-title">
{$days}
{$days > 1 ? 'days' : 'day'}<span class="web-u-color-text-accent">_</span>
</p>
{:else}
<div class="web-title">
<Counter value={$hours} />:<Counter value={$minutes} />:<Counter
value={$seconds}
/><span class="web-u-color-text-accent">_</span>
</div>
{/if}
<img src="/images/icons/gradients/lock.svg" alt="Lock" />
{#if $days > 1}
<p class="web-title">
{$days}
{$days > 1 ? "days" : "day"}<span class="web-u-color-text-accent">_</span>
</p>
{:else}
<div class="web-title">
<Counter value={$hours} />:<Counter value={$minutes} />:<Counter
value={$seconds}
/><span class="web-u-color-text-accent">_</span>
</div>
{/if}
<p class="web-sub-body-500">Countdown to next announcement</p>
<p class="web-sub-body-500">Countdown to next announcement</p>
</div>
<style lang="scss">
.web-card {
height: 25rem;
.web-card {
height: 25rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.web-title {
margin-block-start: 0.75rem;
}
.web-title {
margin-block-start: 0.75rem;
}
.web-sub-body-500 {
margin-block-start: 0.5rem;
}
.web-sub-body-500 {
margin-block-start: 0.5rem;
}
</style>

View File

@@ -1,55 +1,60 @@
<script lang="ts">
import { fade } from 'svelte/transition';
import { fade } from "svelte/transition";
export let value = 0;
export let value = 0;
const getTransform = (value: number) => `translateY(-${value * 100}%)`;
const getTransform = (value: number) => `translateY(-${value * 100}%)`;
function transform(node: HTMLElement, value: number) {
function update(value: number) {
const childNode = [...node.children].find((child) => child.innerHTML === String(value));
if (!childNode) return;
function transform(node: HTMLElement, value: number) {
function update(value: number) {
const childNode = [...node.children].find(
(child) => child.innerHTML === String(value),
);
if (!childNode) return;
const charWidth = childNode.getBoundingClientRect().width;
node.style.transform = `translateY(-${value * 100}%)`;
node.style.width = `${charWidth}px`;
}
update(value);
return { update };
const charWidth = childNode.getBoundingClientRect().width;
node.style.transform = `translateY(-${value * 100}%)`;
node.style.width = `${charWidth}px`;
}
update(value);
return { update };
}
</script>
<div class="wrapper">
{#each value?.toString().padStart(2, '0') as char, index (index)}
<div transition:fade={{ duration: 200 }}>
{#if Number.isNaN(Number(char))}
<span>{char}</span>
{:else}
<ul style:transform={getTransform(Number(char))} use:transform={Number(char)}>
<!-- eslint-disable-next-line @typescript-eslint/no-unused-vars -->
{#each { length: 10 } as _, i}
<li>{i}</li>
{/each}
</ul>
{/if}
</div>
{/each}
{#each value?.toString().padStart(2, "0") as char, index (index)}
<div transition:fade={{ duration: 200 }}>
{#if Number.isNaN(Number(char))}
<span>{char}</span>
{:else}
<ul
style:transform={getTransform(Number(char))}
use:transform={Number(char)}
>
<!-- eslint-disable-next-line @typescript-eslint/no-unused-vars -->
{#each { length: 10 } as _, i}
<li>{i}</li>
{/each}
</ul>
{/if}
</div>
{/each}
</div>
<style>
.wrapper {
display: inline-flex;
overflow: hidden;
}
.wrapper {
display: inline-flex;
overflow: hidden;
}
ul {
display: flex;
flex-direction: column;
align-items: center;
height: 3rem;
line-height: 3rem;
transition: 0.5s ease;
}
ul {
display: flex;
flex-direction: column;
align-items: center;
height: 3rem;
line-height: 3rem;
transition: 0.5s ease;
}
</style>

View File

@@ -1,89 +1,91 @@
<script lang="ts" context="module">
import type { SvelteComponent } from 'svelte';
import type { SvelteComponent } from "svelte";
export type DayType = {
title: string;
release: Date;
animation?: typeof SvelteComponent;
};
export type DayType = {
title: string;
release: Date;
animation?: typeof SvelteComponent;
};
</script>
<script lang="ts">
import { createCountdown } from '../helpers';
import Counter from './Counter.svelte';
import { createCountdown } from "../helpers";
import Counter from "./Counter.svelte";
export let day: DayType;
export let number: number;
export let day: DayType;
export let number: number;
const { hasReleased, days, hours, minutes, seconds } = createCountdown(day.release);
const { hasReleased, days, hours, minutes, seconds } = createCountdown(
day.release,
);
</script>
{#if hasReleased}
<div class="day">
<div class="circle" aria-hidden />
<span class="web-eyebrow web-u-color-text-primary"
>Day {number}<span class="web-u-color-text-accent">_</span></span
>
<h2 class="web-label web-u-color-text-primary">{day.title}</h2>
<div class="slot-wrapper">
<slot />
</div>
<div class="day">
<div class="circle" aria-hidden />
<span class="web-eyebrow web-u-color-text-primary"
>Day {number}<span class="web-u-color-text-accent">_</span></span
>
<h2 class="web-label web-u-color-text-primary">{day.title}</h2>
<div class="slot-wrapper">
<slot />
</div>
</div>
{:else}
<div class="release">
<span class="web-eyebrow web-u-color-text-primary"
>Day {number}<span class="web-u-color-text-accent">_</span></span
>
<div class="bottom">
<div class="countdown web-title">
{#if $hours > 24}
{$days} {$days > 1 ? 'days' : 'day'}
{:else}
<Counter value={$hours} />:<Counter value={$minutes} />:<Counter
value={$seconds}
/>
{/if}
</div>
<a href="/init-0/tickets" class="web-button is-secondary">Register</a>
</div>
<div class="release">
<span class="web-eyebrow web-u-color-text-primary"
>Day {number}<span class="web-u-color-text-accent">_</span></span
>
<div class="bottom">
<div class="countdown web-title">
{#if $hours > 24}
{$days} {$days > 1 ? "days" : "day"}
{:else}
<Counter value={$hours} />:<Counter value={$minutes} />:<Counter
value={$seconds}
/>
{/if}
</div>
<a href="/init-0/tickets" class="web-button is-secondary">Register</a>
</div>
</div>
{/if}
<style lang="scss">
@use '$scss/abstract/mixins/border-gradient' as gradients;
@use "$scss/abstract/mixins/border-gradient" as gradients;
.day,
.release {
@include gradients.border-gradient;
--m-border-radius: 1rem;
--m-border-gradient-before: linear-gradient(
180deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0) 125.11%
);
.day,
.release {
@include gradients.border-gradient;
--m-border-radius: 1rem;
--m-border-gradient-before: linear-gradient(
180deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0) 125.11%
);
display: flex;
flex-direction: column;
position: relative;
display: flex;
flex-direction: column;
position: relative;
background: hsl(var(--web-color-subtle));
overflow: hidden;
background: hsl(var(--web-color-subtle));
overflow: hidden;
height: 7.5rem;
padding: 1.25rem;
height: 7.5rem;
padding: 1.25rem;
flex: 0 0 var(--day-min-w);
flex: 0 0 var(--day-min-w);
}
.day {
height: 100%;
h2 {
margin-block-start: 0.5rem;
position: relative;
max-width: 50%;
}
.day {
height: 100%;
h2 {
margin-block-start: 0.5rem;
position: relative;
max-width: 50%;
}
/* .circle {
/* .circle {
content: '';
background: radial-gradient(
hsl(var(--web-color-accent)) 0%,
@@ -103,27 +105,27 @@
pointer-events: none;
} */
.slot-wrapper {
position: absolute;
height: 100%;
inset-inline-end: 0;
inset-block-end: 0;
translate: 50% 20%;
pointer-events: none;
}
.slot-wrapper {
position: absolute;
height: 100%;
inset-inline-end: 0;
inset-block-end: 0;
translate: 50% 20%;
pointer-events: none;
}
}
.release {
justify-content: center;
gap: 0.5rem;
.release {
justify-content: center;
gap: 0.5rem;
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
}
.countdown {
color: hsl(var(--web-color-primary));
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
}
.countdown {
color: hsl(var(--web-color-primary));
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -1,48 +1,48 @@
<script>
import { browser } from '$app/environment';
import ShineSVG from '../(assets)/shine-bg.svg';
import { browser } from "$app/environment";
import ShineSVG from "../(assets)/shine-bg.svg";
</script>
<div class="ticket-preview" style:opacity={browser ? '1' : '0.5'}>
<slot />
<div class="ticket-preview" style:opacity={browser ? "1" : "0.5"}>
<slot />
<img class="shine" src={ShineSVG} alt="" />
<img class="shine" src={ShineSVG} alt="" />
</div>
<style lang="scss">
.ticket-preview {
--p-border-radius: 1rem;
border: 1px solid hsl(var(--web-color-subtle));
border-radius: var(--p-border-radius);
.ticket-preview {
--p-border-radius: 1rem;
border: 1px solid hsl(var(--web-color-subtle));
border-radius: var(--p-border-radius);
position: relative;
overflow: hidden;
width: 100%;
aspect-ratio: 0.95 / 1;
position: relative;
overflow: hidden;
width: 100%;
aspect-ratio: 0.95 / 1;
display: grid;
place-items: center;
display: grid;
place-items: center;
transition: opacity 0.25s ease;
transition: opacity 0.25s ease;
--base-width: min(40vw, 28.75rem);
--base-width: min(40vw, 28.75rem);
:global(.ticket-holder) {
position: absolute;
left: 50%;
top: 50%;
translate: -50% -50%;
}
.shine {
position: absolute;
inset-block-start: -100px;
inset-inline-end: -100px;
z-index: -1;
}
@media screen and (max-width: 1023px) {
--base-width: min(60vw, 300px);
}
:global(.ticket-holder) {
position: absolute;
left: 50%;
top: 50%;
translate: -50% -50%;
}
.shine {
position: absolute;
inset-block-start: -100px;
inset-inline-end: -100px;
z-index: -1;
}
@media screen and (max-width: 1023px) {
--base-width: min(60vw, 300px);
}
}
</style>

View File

@@ -1,97 +1,102 @@
<script lang="ts">
import { browser } from '$app/environment';
import { melt, type Dialog } from '@melt-ui/svelte';
import { fade, scale } from 'svelte/transition';
import { browser } from "$app/environment";
import { melt, type Dialog } from "@melt-ui/svelte";
import { fade, scale } from "svelte/transition";
export let src: string = 'https://www.youtube.com/embed/XxbJw8PrIkc?si=kOEzUREP0KZoFDY7'; // TODO: REMOVE THIS BEFORE MERGING, THIS IS MOCK DATA
export let src: string =
"https://www.youtube.com/embed/XxbJw8PrIkc?si=kOEzUREP0KZoFDY7"; // TODO: REMOVE THIS BEFORE MERGING, THIS IS MOCK DATA
export let dialog: Dialog;
export let dialog: Dialog;
const {
elements: { portalled, content, overlay },
states: { open }
} = dialog;
const {
elements: { portalled, content, overlay },
states: { open },
} = dialog;
let key = 0;
let key = 0;
function increment() {
key++;
}
function increment() {
key++;
}
let timeout: number;
$: if (!$open && browser) {
clearTimeout(timeout);
timeout = window.setTimeout(increment, 200);
}
let timeout: number;
$: if (!$open && browser) {
clearTimeout(timeout);
timeout = window.setTimeout(increment, 200);
}
</script>
<div use:melt={$portalled}>
<div use:melt={$overlay} class="overlay" transition:fade={{ duration: 150 }} />
<div
use:melt={$overlay}
class="overlay"
transition:fade={{ duration: 150 }}
/>
<div
class="web-media content"
use:melt={$content}
transition:scale={{ duration: 250, start: 0.95 }}
>
{#key key}
<iframe
{src}
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
/>
{/key}
</div>
<div
class="web-media content"
use:melt={$content}
transition:scale={{ duration: 250, start: 0.95 }}
>
{#key key}
<iframe
{src}
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
/>
{/key}
</div>
</div>
<style lang="scss">
.overlay {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1000;
.overlay {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1000;
opacity: 0;
pointer-events: none;
transition: 200ms ease;
opacity: 0;
pointer-events: none;
transition: 200ms ease;
&[data-state='open'] {
opacity: 1;
pointer-events: all;
}
&[data-state="open"] {
opacity: 1;
pointer-events: all;
}
}
.content {
position: fixed;
left: 50%;
top: 50%;
translate: -50% -50%;
display: block;
object-fit: contain;
max-height: 75vh;
width: calc(80%);
aspect-ratio: 16 / 9;
z-index: 1000;
opacity: 0;
transform: scale(0.975);
pointer-events: none;
transition: 200ms ease;
&[data-state="open"] {
opacity: 1;
transform: scale(1);
pointer-events: all;
}
.content {
position: fixed;
left: 50%;
top: 50%;
translate: -50% -50%;
display: block;
object-fit: contain;
max-height: 75vh;
width: calc(80%);
aspect-ratio: 16 / 9;
z-index: 1000;
opacity: 0;
transform: scale(0.975);
pointer-events: none;
transition: 200ms ease;
&[data-state='open'] {
opacity: 1;
transform: scale(1);
pointer-events: all;
}
iframe {
display: block;
inline-size: 100%;
block-size: 100%;
}
iframe {
display: block;
inline-size: 100%;
block-size: 100%;
}
}
</style>

View File

@@ -1,39 +1,39 @@
<script lang="ts" context="module">
const CTX_KEY = Symbol('video-wrapper');
const CTX_KEY = Symbol("video-wrapper");
export const videoCtx = {
get: () => {
return (
getContext<Dialog>(CTX_KEY) ??
createDialog({
preventScroll: false,
forceVisible: true
})
);
},
set: (dialog: Dialog) => {
setContext(CTX_KEY, dialog);
}
};
export const videoCtx = {
get: () => {
return (
getContext<Dialog>(CTX_KEY) ??
createDialog({
preventScroll: false,
forceVisible: true,
})
);
},
set: (dialog: Dialog) => {
setContext(CTX_KEY, dialog);
},
};
</script>
<script lang="ts">
import { createDialog, type Dialog } from '@melt-ui/svelte';
import { getContext, setContext } from 'svelte';
import { createDialog, type Dialog } from "@melt-ui/svelte";
import { getContext, setContext } from "svelte";
const dialog = createDialog({
preventScroll: false,
forceVisible: true
});
videoCtx.set(dialog);
const dialog = createDialog({
preventScroll: false,
forceVisible: true,
});
videoCtx.set(dialog);
const {
states: { open }
} = dialog;
const {
states: { open },
} = dialog;
function openVideo() {
open.set(true);
}
function openVideo() {
open.set(true);
}
</script>
<slot {openVideo} />

View File

@@ -1,32 +1,32 @@
<script lang="ts">
import CountdownCard from '../(components)/CountdownCard.svelte';
import CountdownCard from "../(components)/CountdownCard.svelte";
export let release: Date;
export let day: string | undefined = undefined;
export let release: Date;
export let day: string | undefined = undefined;
let now = new Date();
let interval = setInterval(() => {
if (hasReleased) {
clearInterval(interval);
return;
}
now = new Date();
}, 1000);
let now = new Date();
let interval = setInterval(() => {
if (hasReleased) {
clearInterval(interval);
return;
}
now = new Date();
}, 1000);
$: hasReleased = now >= release;
$: hasReleased = now >= release;
</script>
<h2 class="web-eyebrow web-u-color-text-primary">
<div class="web-dot" />
{#if day !== undefined}
{day}<span class="web-u-color-text-accent">_</span>
{/if}
<div class="web-dot" />
{#if day !== undefined}
{day}<span class="web-u-color-text-accent">_</span>
{/if}
</h2>
<div class="u-margin-block-start-16">
{#if hasReleased}
<slot />
{:else}
<CountdownCard date={release} />
{/if}
{#if hasReleased}
<slot />
{:else}
<CountdownCard date={release} />
{/if}
</div>

View File

@@ -1,275 +1,286 @@
<script lang="ts">
import Day from './Day.svelte';
import illustration from '../(assets)/messaging.png';
import Video from '../(components)/Video.svelte';
import thumbnail from '../(assets)/thumbnail-messaging.png';
import thumbnailProduct from '../(assets)/thumbnail-messaging-product.png';
import twillio from '../(assets)/messaging-1.png';
import { Animations } from '../(animations)';
import VideoWrapper from '../(components)/VideoWrapper.svelte';
import Day from "./Day.svelte";
import illustration from "../(assets)/messaging.png";
import Video from "../(components)/Video.svelte";
import thumbnail from "../(assets)/thumbnail-messaging.png";
import thumbnailProduct from "../(assets)/thumbnail-messaging-product.png";
import twillio from "../(assets)/messaging-1.png";
import { Animations } from "../(animations)";
import VideoWrapper from "../(components)/VideoWrapper.svelte";
export let release: Date;
export let date: string;
export let release: Date;
export let date: string;
</script>
<Day day={date} {release}>
<div class="mosaic">
<a
href="/blog/post/announcing-appwrite-messaging"
class="web-card is-normal has-border-gradient"
style:padding="0"
>
<div style:padding="2rem" style:padding-block-end="0">
<h3 class="web-label web-u-color-text-primary">Messaging</h3>
<p style:margin-block-start="0.625rem">
Introducing multimedia messaging service to communicate to your users across
platforms.
</p>
<div class="web-card-link u-flex u-cross-center" style:margin-block-start="1.25rem">
<span class="text">Announcement</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img src={illustration} alt="" />
<div class="circle" />
</a>
<div class="mosaic">
<a
href="/blog/post/announcing-appwrite-messaging"
class="web-card is-normal has-border-gradient"
style:padding="0"
>
<div style:padding="2rem" style:padding-block-end="0">
<h3 class="web-label web-u-color-text-primary">Messaging</h3>
<p style:margin-block-start="0.625rem">
Introducing multimedia messaging service to communicate to your users
across platforms.
</p>
<div
class="web-card is-normal has-border-gradient"
style="padding: 0.5rem; --p-aspect-ratio: 0;"
class="web-card-link u-flex u-cross-center"
style:margin-block-start="1.25rem"
>
<Video
{thumbnail}
src="https://www.youtube-nocookie.com/embed/w-izHSKXqtU?si=OV30JUel_Zoq10AU&controls=0"
/>
<span class="text">Announcement</span>
<span class="web-icon-arrow-right" />
</div>
<a
href="/blog/post/simplify-messaging-twilio"
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 1.25rem; --p-aspect-ratio: 0;"
>
<h3 class="web-label web-u-color-text-primary" style="max-width: 18.75rem">
How tools like Twilio can simplify messaging for developers
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Article</span>
<span class="web-icon-arrow-right" />
</div>
<img
src={twillio}
alt="Twilio"
style="position: absolute; inset-block-start: 0; inset-inline-end: -2rem;"
/>
</a>
<a
href="/blog/post/push-notifications-best-practices"
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 20px"
>
<h3 class="web-label web-u-color-text-primary" style="max-width: 300px">
Best practices for sending push notifications
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Article</span>
<span class="web-icon-arrow-right" />
</div>
<div>
<Animations.Messaging />
</div>
</a>
<VideoWrapper let:openVideo>
<button
on:click={openVideo}
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3 class="web-label web-u-color-text-primary" style="max-width: 300px">
Product tour
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Watch</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<Video
thumbnail={thumbnailProduct}
--p-aspect-ratio="16/9"
--p-border-radius="0.75rem"
src="https://www.youtube-nocookie.com/embed/QdDgPeuBZ1I?si=YDlxtt3nYe_FZnql&controls=0"
/>
</button>
</VideoWrapper>
<a
href="/docs/products/messaging"
class="web-card is-normal has-border-gradient"
style="padding: 1.25rem"
>
<h3 class="web-label web-u-color-text-primary">Documentation</h3>
<span class="web-card-link u-flex u-cross-center">
<span class="text">Learn more</span>
<span class="web-icon-arrow-right" />
</span>
</a>
<a
href="/init-0/tickets"
class="web-card is-normal has-border-gradient"
style="padding: 1.25rem"
>
<h3 class="web-label web-u-color-text-primary">Win swag</h3>
<span class="web-card-link u-flex u-cross-center">
<span class="text">Enter giveaway</span>
<span class="web-icon-arrow-right" />
</span>
</a>
<a
href="https://discord.com/events/564160730845151244/1209117134417035365"
target="_blank"
rel="noreferrer noopener"
class="web-card is-normal has-border-gradient"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3 class="web-label web-u-color-text-primary">Event: Welcome to Init</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Join</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img
src="/images/community/events/init-0.png"
alt=""
style="aspect-ratio: 16/9; border-radius: 0.75rem; object-fit: cover;"
/>
</a>
</div>
<img src={illustration} alt="" />
<div class="circle" />
</a>
<div
class="web-card is-normal has-border-gradient"
style="padding: 0.5rem; --p-aspect-ratio: 0;"
>
<Video
{thumbnail}
src="https://www.youtube-nocookie.com/embed/w-izHSKXqtU?si=OV30JUel_Zoq10AU&controls=0"
/>
</div>
<a
href="/blog/post/simplify-messaging-twilio"
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 1.25rem; --p-aspect-ratio: 0;"
>
<h3
class="web-label web-u-color-text-primary"
style="max-width: 18.75rem"
>
How tools like Twilio can simplify messaging for developers
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Article</span>
<span class="web-icon-arrow-right" />
</div>
<img
src={twillio}
alt="Twilio"
style="position: absolute; inset-block-start: 0; inset-inline-end: -2rem;"
/>
</a>
<a
href="/blog/post/push-notifications-best-practices"
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 20px"
>
<h3 class="web-label web-u-color-text-primary" style="max-width: 300px">
Best practices for sending push notifications
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Article</span>
<span class="web-icon-arrow-right" />
</div>
<div>
<Animations.Messaging />
</div>
</a>
<VideoWrapper let:openVideo>
<button
on:click={openVideo}
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3
class="web-label web-u-color-text-primary"
style="max-width: 300px"
>
Product tour
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Watch</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<Video
thumbnail={thumbnailProduct}
--p-aspect-ratio="16/9"
--p-border-radius="0.75rem"
src="https://www.youtube-nocookie.com/embed/QdDgPeuBZ1I?si=YDlxtt3nYe_FZnql&controls=0"
/>
</button>
</VideoWrapper>
<a
href="/docs/products/messaging"
class="web-card is-normal has-border-gradient"
style="padding: 1.25rem"
>
<h3 class="web-label web-u-color-text-primary">Documentation</h3>
<span class="web-card-link u-flex u-cross-center">
<span class="text">Learn more</span>
<span class="web-icon-arrow-right" />
</span>
</a>
<a
href="/init-0/tickets"
class="web-card is-normal has-border-gradient"
style="padding: 1.25rem"
>
<h3 class="web-label web-u-color-text-primary">Win swag</h3>
<span class="web-card-link u-flex u-cross-center">
<span class="text">Enter giveaway</span>
<span class="web-icon-arrow-right" />
</span>
</a>
<a
href="https://discord.com/events/564160730845151244/1209117134417035365"
target="_blank"
rel="noreferrer noopener"
class="web-card is-normal has-border-gradient"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3 class="web-label web-u-color-text-primary">
Event: Welcome to Init
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Join</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img
src="/images/community/events/init-0.png"
alt=""
style="aspect-ratio: 16/9; border-radius: 0.75rem; object-fit: cover;"
/>
</a>
</div>
</Day>
<style lang="scss">
p {
text-wrap: balance;
p {
text-wrap: balance;
}
.mosaic {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: repeat(2, 224px) repeat(2, 126px) 60px;
gap: 2rem;
min-height: 660px;
> :nth-child(1) {
grid-column: 1 / 8;
grid-row: 1 / 3;
position: relative;
overflow: hidden;
img {
display: block;
margin-block-start: 1rem;
z-index: 10;
}
.circle {
$size: 200px;
width: $size;
height: $size;
background: hsl(var(--web-color-accent));
filter: blur(200px);
position: absolute;
inset-block-end: calc(-1 * $size / 2);
inset-inline-start: 50%;
translate: -50%;
z-index: 1;
}
}
.mosaic {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: repeat(2, 224px) repeat(2, 126px) 60px;
gap: 2rem;
min-height: 660px;
> :nth-child(1) {
grid-column: 1 / 8;
grid-row: 1 / 3;
position: relative;
overflow: hidden;
img {
display: block;
margin-block-start: 1rem;
z-index: 10;
}
.circle {
$size: 200px;
width: $size;
height: $size;
background: hsl(var(--web-color-accent));
filter: blur(200px);
position: absolute;
inset-block-end: calc(-1 * $size / 2);
inset-inline-start: 50%;
translate: -50%;
z-index: 1;
}
}
> :nth-child(2) {
grid-column: 8 / 13;
grid-row: 1 / 2;
}
> :nth-child(3) {
grid-column: 8 / 13;
grid-row: 2 / 3;
}
> :nth-child(4) {
grid-column: 1 / 7;
grid-row: 3 / 4;
> div:last-child {
position: absolute;
inset-block-start: 1.5rem;
inset-inline-end: -7rem;
}
@media screen and (max-width: 1023px) {
height: 224px;
> div:last-child {
inset-block-start: unset;
inset-block-end: 1rem;
inset-inline-start: 3rem;
inset-inline-end: unset;
}
}
}
> :nth-child(5) {
grid-column: 7 / 13;
grid-row: 3 / 4;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
}
}
> :nth-child(6) {
grid-column: 1 / 4;
grid-row: 4 / 5;
}
> :nth-child(7) {
grid-column: 4 / 7;
grid-row: 4 / 5;
}
> :nth-child(8) {
grid-column: 7 / 13;
grid-row: 4 / 5;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
}
}
> :nth-child(9) {
grid-column: 1 / 13;
grid-row: 5 / 6;
}
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
gap: 1rem;
}
.web-card {
.web-card-link {
color: var(--web-color-primary);
}
&:hover {
.web-card-link {
color: hsl(var(--web-color-accent-darker));
}
}
}
> :nth-child(2) {
grid-column: 8 / 13;
grid-row: 1 / 2;
}
> :nth-child(3) {
grid-column: 8 / 13;
grid-row: 2 / 3;
}
> :nth-child(4) {
grid-column: 1 / 7;
grid-row: 3 / 4;
> div:last-child {
position: absolute;
inset-block-start: 1.5rem;
inset-inline-end: -7rem;
}
@media screen and (max-width: 1023px) {
height: 224px;
> div:last-child {
inset-block-start: unset;
inset-block-end: 1rem;
inset-inline-start: 3rem;
inset-inline-end: unset;
}
}
}
> :nth-child(5) {
grid-column: 7 / 13;
grid-row: 3 / 4;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
}
}
> :nth-child(6) {
grid-column: 1 / 4;
grid-row: 4 / 5;
}
> :nth-child(7) {
grid-column: 4 / 7;
grid-row: 4 / 5;
}
> :nth-child(8) {
grid-column: 7 / 13;
grid-row: 4 / 5;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
}
}
> :nth-child(9) {
grid-column: 1 / 13;
grid-row: 5 / 6;
}
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
gap: 1rem;
}
.web-card {
.web-card-link {
color: var(--web-color-primary);
}
&:hover {
.web-card-link {
color: hsl(var(--web-color-accent-darker));
}
}
}
}
</style>

View File

@@ -1,231 +1,244 @@
<script lang="ts">
import { Animations } from '../(animations)';
import illustration from '../(assets)/ssr.png';
import thumbnail from '../(assets)/thumbnail-ssr.png';
import thumbnailProduct from '../(assets)/thumbnail-ssr-product.png';
import VideoWrapper from '../(components)/VideoWrapper.svelte';
import Day from './Day.svelte';
import Video from '../(components)/Video.svelte';
import { Animations } from "../(animations)";
import illustration from "../(assets)/ssr.png";
import thumbnail from "../(assets)/thumbnail-ssr.png";
import thumbnailProduct from "../(assets)/thumbnail-ssr-product.png";
import VideoWrapper from "../(components)/VideoWrapper.svelte";
import Day from "./Day.svelte";
import Video from "../(components)/Video.svelte";
export let release: Date;
export let date: string;
export let release: Date;
export let date: string;
</script>
<Day day={date} {release}>
<div class="mosaic">
<a
href="/blog/post/introducing-support-for-server-side-rendering"
class="web-card is-normal has-border-gradient"
style:padding="0"
>
<div style:padding="2rem" style:padding-block-end="0">
<h3 class="web-label web-u-color-text-primary">Server-side rendering</h3>
<p style:margin-block-start="0.625rem">
We introduce improved support for server-side rendering in Appwrite
Authentication.
</p>
<div class="web-card-link u-flex u-cross-center" style:margin-block-start="1.25rem">
<span class="text">Announcement</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img src={illustration} alt="" />
<div class="circle" />
</a>
<div class="mosaic">
<a
href="/blog/post/introducing-support-for-server-side-rendering"
class="web-card is-normal has-border-gradient"
style:padding="0"
>
<div style:padding="2rem" style:padding-block-end="0">
<h3 class="web-label web-u-color-text-primary">
Server-side rendering
</h3>
<p style:margin-block-start="0.625rem">
We introduce improved support for server-side rendering in Appwrite
Authentication.
</p>
<div
class="web-card is-normal has-border-gradient"
style="padding: 0.5rem; --p-aspect-ratio: 0;"
class="web-card-link u-flex u-cross-center"
style:margin-block-start="1.25rem"
>
<Video
src="https://www.youtube-nocookie.com/embed/jeL4cSovOBA?si=0tMDecmUucWOYASg"
{thumbnail}
/>
<span class="text">Announcement</span>
<span class="web-icon-arrow-right" />
</div>
<a
href="/blog/post/csr-vs-ssr-with-nextjs"
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 1.25rem; --p-aspect-ratio: 0;"
>
<h3 class="web-label web-u-color-text-primary" style="max-width: 18.75rem">CSR vs SSR</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Article</span>
<span class="web-icon-arrow-right" />
</div>
<div>
<Animations.SSR />
</div>
</a>
<a
href="https://discord.com/events/564160730845151244/1209117245859569754"
target="_blank"
rel="noreferrer noopener"
class="web-card is-normal has-border-gradient"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3 class="web-label web-u-color-text-primary">Event: Speed</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Join</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img
src="/images/community/events/init-1.png"
alt=""
style="aspect-ratio: 16/9; border-radius: 0.75rem; object-fit: cover;"
/>
</a>
<VideoWrapper let:openVideo>
<button
on:click={openVideo}
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3 class="web-label web-u-color-text-primary" style="max-width: 300px">
Product tour
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Watch</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<Video
thumbnail={thumbnailProduct}
--p-aspect-ratio="16/9"
--p-border-radius="0.75rem"
src="https://www.youtube-nocookie.com/embed/7LN05c-ov_0?si=Gb0gS-k4M24F1AOg"
/>
</button>
</VideoWrapper>
<a
href="/docs/products/auth/server-side-rendering"
class="web-card is-normal has-border-gradient"
style="padding: 1.25rem"
>
<h3 class="web-label web-u-color-text-primary">Documentation</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Learn more</span>
<span class="web-icon-arrow-right" />
</div>
</a>
</div>
<img src={illustration} alt="" />
<div class="circle" />
</a>
<div
class="web-card is-normal has-border-gradient"
style="padding: 0.5rem; --p-aspect-ratio: 0;"
>
<Video
src="https://www.youtube-nocookie.com/embed/jeL4cSovOBA?si=0tMDecmUucWOYASg"
{thumbnail}
/>
</div>
<a
href="/blog/post/csr-vs-ssr-with-nextjs"
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 1.25rem; --p-aspect-ratio: 0;"
>
<h3
class="web-label web-u-color-text-primary"
style="max-width: 18.75rem"
>
CSR vs SSR
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Article</span>
<span class="web-icon-arrow-right" />
</div>
<div>
<Animations.SSR />
</div>
</a>
<a
href="https://discord.com/events/564160730845151244/1209117245859569754"
target="_blank"
rel="noreferrer noopener"
class="web-card is-normal has-border-gradient"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3 class="web-label web-u-color-text-primary">Event: Speed</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Join</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img
src="/images/community/events/init-1.png"
alt=""
style="aspect-ratio: 16/9; border-radius: 0.75rem; object-fit: cover;"
/>
</a>
<VideoWrapper let:openVideo>
<button
on:click={openVideo}
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3
class="web-label web-u-color-text-primary"
style="max-width: 300px"
>
Product tour
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Watch</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<Video
thumbnail={thumbnailProduct}
--p-aspect-ratio="16/9"
--p-border-radius="0.75rem"
src="https://www.youtube-nocookie.com/embed/7LN05c-ov_0?si=Gb0gS-k4M24F1AOg"
/>
</button>
</VideoWrapper>
<a
href="/docs/products/auth/server-side-rendering"
class="web-card is-normal has-border-gradient"
style="padding: 1.25rem"
>
<h3 class="web-label web-u-color-text-primary">Documentation</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Learn more</span>
<span class="web-icon-arrow-right" />
</div>
</a>
</div>
</Day>
<style lang="scss">
p {
text-wrap: balance;
p {
text-wrap: balance;
}
.mosaic {
display: grid;
grid-template-columns: repeat(24, 1fr);
grid-template-rows: repeat(2, 224px) 126px 60px;
gap: 2rem;
min-height: 660px;
> :nth-child(1) {
grid-column: 1 / 15;
grid-row: 1 / 3;
position: relative;
overflow: hidden;
img {
display: block;
margin-block-start: 1rem;
position: relative;
z-index: 10;
}
.circle {
$size: 200px;
width: $size;
height: $size;
background: hsl(var(--web-color-accent));
filter: blur(200px);
position: absolute;
inset-block-end: calc(-1 * $size / 2);
inset-inline-start: 50%;
translate: -50%;
z-index: 1;
}
}
.mosaic {
display: grid;
grid-template-columns: repeat(24, 1fr);
grid-template-rows: repeat(2, 224px) 126px 60px;
gap: 2rem;
min-height: 660px;
> :nth-child(1) {
grid-column: 1 / 15;
grid-row: 1 / 3;
position: relative;
overflow: hidden;
img {
display: block;
margin-block-start: 1rem;
position: relative;
z-index: 10;
}
.circle {
$size: 200px;
width: $size;
height: $size;
background: hsl(var(--web-color-accent));
filter: blur(200px);
position: absolute;
inset-block-end: calc(-1 * $size / 2);
inset-inline-start: 50%;
translate: -50%;
z-index: 1;
}
}
> :nth-child(2) {
grid-column: 15 / 25;
grid-row: 1 / 2;
}
> :nth-child(3) {
grid-column: 15 / 25;
grid-row: 2 / 3;
> div:last-child {
position: absolute;
inset-block-start: 2rem;
inset-inline-end: -3rem;
}
@media screen and (max-width: 1023px) {
height: 280px;
> div:last-child {
inset-block-start: unset;
inset-block-end: -7rem;
inset-inline-end: -3rem;
}
}
}
> :nth-child(4) {
grid-column: 1 / 10;
grid-row: 3 / 4;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
}
}
> :nth-child(5) {
grid-column: 10 / 19;
grid-row: 3 / 4;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
}
}
> :nth-child(6) {
grid-column: 19 / 25;
grid-row: 3 / 4;
}
> :nth-child(7) {
grid-column: 1 / 25;
grid-row: 4 / 5;
}
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
gap: 1rem;
}
.web-card {
.web-card-link {
color: var(--web-color-primary);
}
&:hover {
.web-card-link {
color: hsl(var(--web-color-accent-darker));
}
}
}
> :nth-child(2) {
grid-column: 15 / 25;
grid-row: 1 / 2;
}
> :nth-child(3) {
grid-column: 15 / 25;
grid-row: 2 / 3;
> div:last-child {
position: absolute;
inset-block-start: 2rem;
inset-inline-end: -3rem;
}
@media screen and (max-width: 1023px) {
height: 280px;
> div:last-child {
inset-block-start: unset;
inset-block-end: -7rem;
inset-inline-end: -3rem;
}
}
}
> :nth-child(4) {
grid-column: 1 / 10;
grid-row: 3 / 4;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
}
}
> :nth-child(5) {
grid-column: 10 / 19;
grid-row: 3 / 4;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
}
}
> :nth-child(6) {
grid-column: 19 / 25;
grid-row: 3 / 4;
}
> :nth-child(7) {
grid-column: 1 / 25;
grid-row: 4 / 5;
}
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
gap: 1rem;
}
.web-card {
.web-card-link {
color: var(--web-color-primary);
}
&:hover {
.web-card-link {
color: hsl(var(--web-color-accent-darker));
}
}
}
}
</style>

View File

@@ -1,225 +1,237 @@
<script lang="ts">
import enumPng from '../(assets)/enum.png';
import twoFa from '../(assets)/2fa.png';
import thumbnail from '../(assets)/thumbnail-2fa.png';
import thumbnailEvent from '../(assets)/thumbnail-2fa-event.png';
import VideoWrapper from '../(components)/VideoWrapper.svelte';
import Day from './Day.svelte';
import Video from '../(components)/Video.svelte';
import enumPng from "../(assets)/enum.png";
import twoFa from "../(assets)/2fa.png";
import thumbnail from "../(assets)/thumbnail-2fa.png";
import thumbnailEvent from "../(assets)/thumbnail-2fa-event.png";
import VideoWrapper from "../(components)/VideoWrapper.svelte";
import Day from "./Day.svelte";
import Video from "../(components)/Video.svelte";
export let release: Date;
export let date: string;
export let release: Date;
export let date: string;
</script>
<Day day={date} {release}>
<div class="mosaic">
<a
href="/blog/post/introducing-enum-sdk-support"
class="web-card is-normal has-border-gradient"
style:padding="0"
<div class="mosaic">
<a
href="/blog/post/introducing-enum-sdk-support"
class="web-card is-normal has-border-gradient"
style:padding="0"
>
<div style:padding="2rem" style:padding-block-end="0">
<h3 class="web-label web-u-color-text-primary">Enum SDK support</h3>
<p style:margin-block-start="0.625rem">
A new feature that enhances the experience across all Appwrite client
and server-side SDKs.
</p>
<div
class="web-card-link u-flex u-cross-center"
style:margin-block-start="1.25rem"
>
<div style:padding="2rem" style:padding-block-end="0">
<h3 class="web-label web-u-color-text-primary">Enum SDK support</h3>
<p style:margin-block-start="0.625rem">
A new feature that enhances the experience across all Appwrite client and
server-side SDKs.
</p>
<div class="web-card-link u-flex u-cross-center" style:margin-block-start="1.25rem">
<span class="text">Announcement</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img src={enumPng} alt="" />
<div class="circle" />
</a>
<a
href="/blog/post/announcing-two-factor-authentication"
class="web-card is-normal has-border-gradient"
style:padding="0"
<span class="text">Announcement</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img src={enumPng} alt="" />
<div class="circle" />
</a>
<a
href="/blog/post/announcing-two-factor-authentication"
class="web-card is-normal has-border-gradient"
style:padding="0"
>
<div style:padding="2rem" style:padding-block-end="0">
<h3 class="web-label web-u-color-text-primary">
Two-factor authentication
</h3>
<p style:margin-block-start="0.625rem">
Add an additional layer of protection to your end users accounts with
2FA.
</p>
<div
class="web-card-link u-flex u-cross-center"
style:margin-block-start="1.25rem"
>
<div style:padding="2rem" style:padding-block-end="0">
<h3 class="web-label web-u-color-text-primary">Two-factor authentication</h3>
<p style:margin-block-start="0.625rem">
Add an additional layer of protection to your end users accounts with 2FA.
</p>
<div class="web-card-link u-flex u-cross-center" style:margin-block-start="1.25rem">
<span class="text">Announcement</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img src={twoFa} alt="" />
<div class="circle" />
</a>
<a
href="https://discord.com/events/564160730845151244/1209117412247609354"
target="_blank"
rel="noreferrer noopener"
class="web-card is-normal has-border-gradient"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3 class="web-label web-u-color-text-primary">Event: Safety</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Join</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img
src={thumbnailEvent}
alt=""
style="aspect-ratio: 268/110; border-radius: 0.75rem; object-fit: cover;"
/>
</a>
<VideoWrapper let:openVideo>
<button
on:click={openVideo}
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3 class="web-label web-u-color-text-primary" style="max-width: 300px">
Release video
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Watch</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<Video
src="https://www.youtube-nocookie.com/embed/hpdUXOFay4M?si=TPO8CistphsTOCas&amp;controls=0"
{thumbnail}
--p-aspect-ratio="268/110"
--p-border-radius="0.75rem"
/>
</button>
</VideoWrapper>
<span class="text">Announcement</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img src={twoFa} alt="" />
<div class="circle" />
</a>
<a
href="https://discord.com/events/564160730845151244/1209117412247609354"
target="_blank"
rel="noreferrer noopener"
class="web-card is-normal has-border-gradient"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3 class="web-label web-u-color-text-primary">Event: Safety</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Join</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img
src={thumbnailEvent}
alt=""
style="aspect-ratio: 268/110; border-radius: 0.75rem; object-fit: cover;"
/>
</a>
<VideoWrapper let:openVideo>
<button
on:click={openVideo}
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3
class="web-label web-u-color-text-primary"
style="max-width: 300px"
>
Release video
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Watch</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<Video
src="https://www.youtube-nocookie.com/embed/hpdUXOFay4M?si=TPO8CistphsTOCas&amp;controls=0"
{thumbnail}
--p-aspect-ratio="268/110"
--p-border-radius="0.75rem"
/>
</button>
</VideoWrapper>
<a
href="/docs/sdks#enums"
class="web-card is-normal has-border-gradient"
style="padding: 1.25rem"
>
<h3 class="web-label web-u-color-text-primary">Enum Documentation</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Learn more</span>
<span class="web-icon-arrow-right" />
</div>
</a>
<a
href="/docs/products/auth/2fa"
class="web-card is-normal has-border-gradient"
style="padding: 1.25rem"
>
<h3 class="web-label web-u-color-text-primary">2FA Documentation</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Learn more</span>
<span class="web-icon-arrow-right" />
</div>
</a>
</div>
<a
href="/docs/sdks#enums"
class="web-card is-normal has-border-gradient"
style="padding: 1.25rem"
>
<h3 class="web-label web-u-color-text-primary">Enum Documentation</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Learn more</span>
<span class="web-icon-arrow-right" />
</div>
</a>
<a
href="/docs/products/auth/2fa"
class="web-card is-normal has-border-gradient"
style="padding: 1.25rem"
>
<h3 class="web-label web-u-color-text-primary">2FA Documentation</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Learn more</span>
<span class="web-icon-arrow-right" />
</div>
</a>
</div>
</Day>
<style lang="scss">
p {
text-wrap: balance;
p {
text-wrap: balance;
}
.mosaic {
display: grid;
grid-template-columns: repeat(24, 1fr);
grid-template-rows: 480px repeat(2, 120px) 60px;
gap: 2rem;
min-height: 660px;
> :nth-child(1) {
grid-column: 1 / 13;
grid-row: 1;
}
.mosaic {
display: grid;
grid-template-columns: repeat(24, 1fr);
grid-template-rows: 480px repeat(2, 120px) 60px;
gap: 2rem;
min-height: 660px;
> :nth-child(1) {
grid-column: 1 / 13;
grid-row: 1;
}
> :nth-child(2) {
grid-column: 13 / 25;
grid-row: 1;
}
> :nth-child(1),
> :nth-child(2) {
position: relative;
overflow: hidden;
img {
display: block;
margin-block-start: 1rem;
position: relative;
z-index: 10;
}
.circle {
$size: 200px;
width: $size;
height: $size;
background: hsl(var(--web-color-accent));
filter: blur(200px);
position: absolute;
inset-block-end: calc(-1 * $size / 2);
inset-inline-start: 50%;
translate: -50%;
z-index: 1;
}
}
> :nth-child(3) {
grid-column: 1 / 13;
grid-row: 2;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
}
}
> :nth-child(4) {
grid-column: 13 / 25;
grid-row: 2;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
}
}
> :nth-child(5) {
grid-column: 1 / 13;
grid-row: 3;
}
> :nth-child(6) {
grid-column: 13 / 25;
grid-row: 3;
}
> :nth-child(7) {
grid-column: 1 / 25;
grid-row: 4 / 5;
}
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
gap: 1rem;
}
.web-card {
.web-card-link {
color: var(--web-color-primary);
}
&:hover {
.web-card-link {
color: hsl(var(--web-color-accent-darker));
}
}
}
> :nth-child(2) {
grid-column: 13 / 25;
grid-row: 1;
}
> :nth-child(1),
> :nth-child(2) {
position: relative;
overflow: hidden;
img {
display: block;
margin-block-start: 1rem;
position: relative;
z-index: 10;
}
.circle {
$size: 200px;
width: $size;
height: $size;
background: hsl(var(--web-color-accent));
filter: blur(200px);
position: absolute;
inset-block-end: calc(-1 * $size / 2);
inset-inline-start: 50%;
translate: -50%;
z-index: 1;
}
}
> :nth-child(3) {
grid-column: 1 / 13;
grid-row: 2;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
}
}
> :nth-child(4) {
grid-column: 13 / 25;
grid-row: 2;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
}
}
> :nth-child(5) {
grid-column: 1 / 13;
grid-row: 3;
}
> :nth-child(6) {
grid-column: 13 / 25;
grid-row: 3;
}
> :nth-child(7) {
grid-column: 1 / 25;
grid-row: 4 / 5;
}
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
gap: 1rem;
}
.web-card {
.web-card-link {
color: var(--web-color-primary);
}
&:hover {
.web-card-link {
color: hsl(var(--web-color-accent-darker));
}
}
}
}
</style>

View File

@@ -1,243 +1,252 @@
<script lang="ts">
import { Animations } from '../(animations)';
import illustration from '../(assets)/operators.png';
import thumbnail from '../(assets)/thumbnail-db.png';
import thumbnailProduct from '../(assets)/thumbnail-db-product.png';
import thumbnailEvent from '../(assets)/thumbnail-db-event.png';
import VideoWrapper from '../(components)/VideoWrapper.svelte';
import { Animations } from "../(animations)";
import illustration from "../(assets)/operators.png";
import thumbnail from "../(assets)/thumbnail-db.png";
import thumbnailProduct from "../(assets)/thumbnail-db-product.png";
import thumbnailEvent from "../(assets)/thumbnail-db-event.png";
import VideoWrapper from "../(components)/VideoWrapper.svelte";
import Day from './Day.svelte';
import Video from '../(components)/Video.svelte';
import Day from "./Day.svelte";
import Video from "../(components)/Video.svelte";
export let release: Date;
export let date: string;
export let release: Date;
export let date: string;
</script>
<Day day={date} {release}>
<div class="mosaic">
<a
href="blog/post/introducing-new-database-operators"
class="web-card is-normal has-border-gradient"
style:padding="0"
>
<div style:padding="2rem" style:padding-block-end="0">
<h3 class="web-label web-u-color-text-primary">Database operators</h3>
<p style:margin-block-start="0.625rem">
Announcing a new set of query methods, array contains, string contains, and OR
operators.
</p>
<div class="web-card-link u-flex u-cross-center" style:margin-block-start="1.25rem">
<span class="text">Announcement</span>
<span class="web-icon-arrow-right" />
</div>
<img src={illustration} alt="" />
<div class="circle" />
</div>
</a>
<div class="mosaic">
<a
href="blog/post/introducing-new-database-operators"
class="web-card is-normal has-border-gradient"
style:padding="0"
>
<div style:padding="2rem" style:padding-block-end="0">
<h3 class="web-label web-u-color-text-primary">Database operators</h3>
<p style:margin-block-start="0.625rem">
Announcing a new set of query methods, array contains, string
contains, and OR operators.
</p>
<div
class="web-card is-normal has-border-gradient"
style="padding: 0.5rem; --p-aspect-ratio: 0;"
class="web-card-link u-flex u-cross-center"
style:margin-block-start="1.25rem"
>
<Video
src="https://www.youtube-nocookie.com/embed/73flN6mZqAs?si=3hUI26G9DDVDzJG4&amp;controls=0"
{thumbnail}
/>
<span class="text">Announcement</span>
<span class="web-icon-arrow-right" />
</div>
<a
href="https://discord.com/events/564160730845151244/1209117457294295121"
target="_blank"
rel="noopener noreferrer"
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3 class="web-label web-u-color-text-primary" style="max-width: 300px">
Event: Logic
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Join</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img
src={thumbnailEvent}
alt=""
style="aspect-ratio: 268 / 208; border-radius: 0.75rem; object-fit: cover;"
/>
</a>
<a
href="/blog/post/understand-data-queries"
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 20px"
>
<h3 class="web-label web-u-color-text-primary" style="max-width: 11.25rem">
Understanding Data Queries
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Article</span>
<span class="web-icon-arrow-right" />
</div>
<div>
<Animations.Operators />
</div>
</a>
<VideoWrapper let:openVideo>
<button
on:click={openVideo}
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3 class="web-label web-u-color-text-primary" style="max-width: 300px">
Product tour
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Watch</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<Video
src="https://www.youtube-nocookie.com/embed/IMgl9f_iht4?si=2tpXRe_WXN7-3YzU&amp;controls=0"
thumbnail={thumbnailProduct}
--p-aspect-ratio="16/9"
--p-border-radius="0.75rem"
/>
</button>
</VideoWrapper>
<a
href="/docs/products/databases/queries"
class="web-card is-normal has-border-gradient"
style="padding: 1.25rem"
>
<h3 class="web-label web-u-color-text-primary">Documentation</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Learn more</span>
<span class="web-icon-arrow-right" />
</div>
</a>
<img src={illustration} alt="" />
<div class="circle" />
</div>
</a>
<div
class="web-card is-normal has-border-gradient"
style="padding: 0.5rem; --p-aspect-ratio: 0;"
>
<Video
src="https://www.youtube-nocookie.com/embed/73flN6mZqAs?si=3hUI26G9DDVDzJG4&amp;controls=0"
{thumbnail}
/>
</div>
<a
href="https://discord.com/events/564160730845151244/1209117457294295121"
target="_blank"
rel="noopener noreferrer"
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3 class="web-label web-u-color-text-primary" style="max-width: 300px">
Event: Logic
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Join</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img
src={thumbnailEvent}
alt=""
style="aspect-ratio: 268 / 208; border-radius: 0.75rem; object-fit: cover;"
/>
</a>
<a
href="/blog/post/understand-data-queries"
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 20px"
>
<h3
class="web-label web-u-color-text-primary"
style="max-width: 11.25rem"
>
Understanding Data Queries
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Article</span>
<span class="web-icon-arrow-right" />
</div>
<div>
<Animations.Operators />
</div>
</a>
<VideoWrapper let:openVideo>
<button
on:click={openVideo}
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3
class="web-label web-u-color-text-primary"
style="max-width: 300px"
>
Product tour
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Watch</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<Video
src="https://www.youtube-nocookie.com/embed/IMgl9f_iht4?si=2tpXRe_WXN7-3YzU&amp;controls=0"
thumbnail={thumbnailProduct}
--p-aspect-ratio="16/9"
--p-border-radius="0.75rem"
/>
</button>
</VideoWrapper>
<a
href="/docs/products/databases/queries"
class="web-card is-normal has-border-gradient"
style="padding: 1.25rem"
>
<h3 class="web-label web-u-color-text-primary">Documentation</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Learn more</span>
<span class="web-icon-arrow-right" />
</div>
</a>
</div>
</Day>
<style lang="scss">
p {
text-wrap: balance;
p {
text-wrap: balance;
}
.mosaic {
display: grid;
grid-template-columns: repeat(24, 1fr);
grid-template-rows: repeat(2, 224px) 126px 60px;
gap: 2rem;
min-height: 660px;
> :nth-child(1) {
grid-column: 1 / 15;
grid-row: 1 / 3;
position: relative;
overflow: hidden;
img {
display: block;
margin-block-start: 1rem;
position: relative;
z-index: 10;
}
.circle {
$size: 200px;
width: $size;
height: $size;
background: hsl(var(--web-color-accent));
filter: blur(200px);
position: absolute;
inset-block-end: calc(-1 * $size / 2);
inset-inline-start: 50%;
translate: -50%;
z-index: 1;
}
}
.mosaic {
display: grid;
grid-template-columns: repeat(24, 1fr);
grid-template-rows: repeat(2, 224px) 126px 60px;
gap: 2rem;
min-height: 660px;
> :nth-child(1) {
grid-column: 1 / 15;
grid-row: 1 / 3;
position: relative;
overflow: hidden;
img {
display: block;
margin-block-start: 1rem;
position: relative;
z-index: 10;
}
.circle {
$size: 200px;
width: $size;
height: $size;
background: hsl(var(--web-color-accent));
filter: blur(200px);
position: absolute;
inset-block-end: calc(-1 * $size / 2);
inset-inline-start: 50%;
translate: -50%;
z-index: 1;
}
}
> :nth-child(2) {
grid-column: 15 / 25;
grid-row: 1 / 2;
}
> :nth-child(3) {
grid-column: 15 / 25;
grid-row: 2 / 3;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
// gap: 1rem;
}
}
> :nth-child(4) {
grid-column: 1 / 10;
grid-row: 3 / 4;
> div:last-child {
position: absolute;
inset-block-start: 0rem;
inset-inline-end: -14rem;
transform: scale(0.75);
}
@media screen and (max-width: 1023px) {
height: 280px;
> div:last-child {
transform: scale(1);
inset-block-start: unset;
inset-block-end: 1rem;
inset-inline-start: 2rem;
inset-inline-end: unset;
}
}
}
> :nth-child(5) {
grid-column: 10 / 19;
grid-row: 3 / 4;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
// gap: 1rem;
}
}
> :nth-child(6) {
grid-column: 19 / 25;
grid-row: 3 / 4;
}
> :nth-child(7) {
grid-column: 1 / 25;
grid-row: 4 / 5;
}
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
gap: 1rem;
}
.web-card {
.web-card-link {
color: var(--web-color-primary);
}
&:hover {
.web-card-link {
color: hsl(var(--web-color-accent-darker));
}
}
}
> :nth-child(2) {
grid-column: 15 / 25;
grid-row: 1 / 2;
}
> :nth-child(3) {
grid-column: 15 / 25;
grid-row: 2 / 3;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
// gap: 1rem;
}
}
> :nth-child(4) {
grid-column: 1 / 10;
grid-row: 3 / 4;
> div:last-child {
position: absolute;
inset-block-start: 0rem;
inset-inline-end: -14rem;
transform: scale(0.75);
}
@media screen and (max-width: 1023px) {
height: 280px;
> div:last-child {
transform: scale(1);
inset-block-start: unset;
inset-block-end: 1rem;
inset-inline-start: 2rem;
inset-inline-end: unset;
}
}
}
> :nth-child(5) {
grid-column: 10 / 19;
grid-row: 3 / 4;
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
// gap: 1rem;
}
}
> :nth-child(6) {
grid-column: 19 / 25;
grid-row: 3 / 4;
}
> :nth-child(7) {
grid-column: 1 / 25;
grid-row: 4 / 5;
}
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
gap: 1rem;
}
.web-card {
.web-card-link {
color: var(--web-color-primary);
}
&:hover {
.web-card-link {
color: hsl(var(--web-color-accent-darker));
}
}
}
}
</style>

View File

@@ -1,147 +1,150 @@
<script lang="ts">
import illustration from '../(assets)/integrations.png';
import thumbnail from '../(assets)/thumbnail-runtimes-event.png';
import Day from './Day.svelte';
import illustration from "../(assets)/integrations.png";
import thumbnail from "../(assets)/thumbnail-runtimes-event.png";
import Day from "./Day.svelte";
export let release: Date;
export let date: string;
export let release: Date;
export let date: string;
</script>
<Day day={date} {release}>
<div class="mosaic">
<a
href="/blog/post/announcing-more-and-updated-runtimes"
class="web-card is-normal has-border-gradient"
style:padding="0"
<div class="mosaic">
<a
href="/blog/post/announcing-more-and-updated-runtimes"
class="web-card is-normal has-border-gradient"
style:padding="0"
>
<div style:padding="2rem" style:padding-block-end="0">
<h3 class="web-label web-u-color-text-primary">Updated runtimes</h3>
<p style:margin-block-start="0.625rem">
The latest versions of Bun, Dart, Deno, PHP, Ruby, Kotlin, Java,
Swift, and Node were added to our Cloud runtime ecosystem.
</p>
<div
class="web-card-link u-flex u-cross-center"
style:margin-block-start="1.25rem"
>
<div style:padding="2rem" style:padding-block-end="0">
<h3 class="web-label web-u-color-text-primary">Updated runtimes</h3>
<p style:margin-block-start="0.625rem">
The latest versions of Bun, Dart, Deno, PHP, Ruby, Kotlin, Java, Swift, and Node
were added to our Cloud runtime ecosystem.
</p>
<div class="web-card-link u-flex u-cross-center" style:margin-block-start="1.25rem">
<span class="text">Announcement</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img src={illustration} alt="" />
<div class="circle" />
</a>
<a
href="/docs/products/functions/runtimes#available-runtimes"
class="web-card is-normal has-border-gradient"
style="padding: 1.25rem"
>
<h3 class="web-label web-u-color-text-primary">Documentation</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Learn more</span>
<span class="web-icon-arrow-right" />
</div>
</a>
<span class="text">Announcement</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img src={illustration} alt="" />
<div class="circle" />
</a>
<a
href="/docs/products/functions/runtimes#available-runtimes"
class="web-card is-normal has-border-gradient"
style="padding: 1.25rem"
>
<h3 class="web-label web-u-color-text-primary">Documentation</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Learn more</span>
<span class="web-icon-arrow-right" />
</div>
</a>
<a
href="https://discord.com/events/564160730845151244/1209117535723851776"
rel="noopener noreferrer"
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3 class="web-label web-u-color-text-primary" style="max-width: 300px">
Closing party
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Watch</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img
src={thumbnail}
alt=""
style="aspect-ratio: 268 / 208; border-radius: 0.75rem; object-fit: cover;"
/>
</a>
</div>
<a
href="https://discord.com/events/564160730845151244/1209117535723851776"
rel="noopener noreferrer"
class="web-card is-normal has-border-gradient u-overflow-hidden"
style="padding: 0.5rem; display: flex; justify-content: space-between; "
>
<div style="padding: 0.75rem;">
<h3 class="web-label web-u-color-text-primary" style="max-width: 300px">
Closing party
</h3>
<div class="web-card-link u-flex u-cross-center">
<span class="text">Watch</span>
<span class="web-icon-arrow-right" />
</div>
</div>
<img
src={thumbnail}
alt=""
style="aspect-ratio: 268 / 208; border-radius: 0.75rem; object-fit: cover;"
/>
</a>
</div>
</Day>
<style lang="scss">
p {
text-wrap: balance;
p {
text-wrap: balance;
}
.mosaic {
display: grid;
grid-template-columns: repeat(24, 1fr);
grid-template-rows: repeat(2, 224px);
gap: 2rem;
min-height: 660px;
:nth-child(1) {
grid-column: 1 / 15;
grid-row: 1 / 3;
position: relative;
overflow: hidden;
img {
display: block;
margin-block-start: 1rem;
position: relative;
z-index: 10;
}
.circle {
$size: 200px;
width: $size;
height: $size;
background: hsl(var(--web-color-accent));
filter: blur(200px);
position: absolute;
inset-block-end: calc(-1 * $size / 2);
inset-inline-start: 50%;
translate: -50%;
z-index: 1;
}
}
.mosaic {
display: grid;
grid-template-columns: repeat(24, 1fr);
grid-template-rows: repeat(2, 224px);
gap: 2rem;
min-height: 660px;
:nth-child(1) {
grid-column: 1 / 15;
grid-row: 1 / 3;
position: relative;
overflow: hidden;
img {
display: block;
margin-block-start: 1rem;
position: relative;
z-index: 10;
}
.circle {
$size: 200px;
width: $size;
height: $size;
background: hsl(var(--web-color-accent));
filter: blur(200px);
position: absolute;
inset-block-end: calc(-1 * $size / 2);
inset-inline-start: 50%;
translate: -50%;
z-index: 1;
}
}
:nth-child(2) {
grid-column: 15 / 25;
grid-row: 1 / 2;
}
:nth-child(3) {
grid-column: 15 / 25;
grid-row: 2 / 3;
@media screen and (max-width: 1023px) {
display: flex;
// gap: 1rem;
}
}
:nth-child(4) {
grid-column: 1 / 25;
grid-row: 3 / 4;
}
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
gap: 1rem;
}
.web-card {
.web-card-link {
color: var(--web-color-primary);
}
&:hover {
.web-card-link {
color: hsl(var(--web-color-accent-darker));
}
}
}
:nth-child(2) {
grid-column: 15 / 25;
grid-row: 1 / 2;
}
:nth-child(3) {
grid-column: 15 / 25;
grid-row: 2 / 3;
@media screen and (max-width: 1023px) {
display: flex;
// gap: 1rem;
}
}
:nth-child(4) {
grid-column: 1 / 25;
grid-row: 3 / 4;
}
@media screen and (max-width: 1023px) {
display: flex;
flex-direction: column;
gap: 1rem;
}
.web-card {
.web-card-link {
color: var(--web-color-primary);
}
&:hover {
.web-card-link {
color: hsl(var(--web-color-accent-darker));
}
}
}
}
</style>

View File

@@ -1 +1 @@
export const prerender = false;
export const prerender = false;

View File

@@ -1,195 +1,207 @@
import { onMount } from 'svelte';
import { get, writable } from 'svelte/store';
import { onMount } from "svelte";
import { get, writable } from "svelte/store";
import { appwriteInit } from '$lib/appwrite/init';
import { contributors } from '$lib/contributors';
import { getAppwriteUser, type AppwriteUser } from '$lib/utils/console';
import { appwriteInit } from "$lib/appwrite/init";
import { contributors } from "$lib/contributors";
import { getAppwriteUser, type AppwriteUser } from "$lib/utils/console";
import type {
ContributionsMatrix,
TicketData,
TicketDoc,
TicketVariant
} from './tickets/constants';
import { OAuthProvider } from '@appwrite.io/console';
ContributionsMatrix,
TicketData,
TicketDoc,
TicketVariant,
} from "./tickets/constants";
import { OAuthProvider } from "@appwrite.io/console";
export function createCountdown(date: Date) {
const today = new Date();
const hasReleased = today >= date;
const [days, hours, minutes, seconds] = [
writable(0),
writable(0),
writable(0),
writable(0),
];
function update() {
const today = new Date();
const hasReleased = today >= date;
const timeRemaining = date.getTime() - today.getTime();
const [days, hours, minutes, seconds] = [writable(0), writable(0), writable(0), writable(0)];
function update() {
const today = new Date();
const timeRemaining = date.getTime() - today.getTime();
if (timeRemaining <= 0) {
// Target date has passed, stop the countdown
return;
}
const totalSeconds = Math.floor(timeRemaining / 1000);
seconds.set(totalSeconds % 60);
const totalMinutes = Math.floor(totalSeconds / 60);
minutes.set(totalMinutes % 60);
hours.set(Math.floor(totalMinutes / 60));
days.set(Math.ceil(get(hours) / 24));
if (timeRemaining <= 0) {
// Target date has passed, stop the countdown
return;
}
update();
const totalSeconds = Math.floor(timeRemaining / 1000);
seconds.set(totalSeconds % 60);
const totalMinutes = Math.floor(totalSeconds / 60);
minutes.set(totalMinutes % 60);
hours.set(Math.floor(totalMinutes / 60));
days.set(Math.ceil(get(hours) / 24));
}
onMount(() => {
let frame: number;
update();
function updateFrame() {
update();
// Request the next animation frame to keep updating the countdown
frame = requestAnimationFrame(() => {
updateFrame();
});
}
onMount(() => {
let frame: number;
function updateFrame() {
update();
// Request the next animation frame to keep updating the countdown
frame = requestAnimationFrame(() => {
updateFrame();
});
}
updateFrame();
return () => cancelAnimationFrame(frame);
});
return () => cancelAnimationFrame(frame);
});
return {
hasReleased,
days,
hours,
minutes,
seconds
};
return {
hasReleased,
days,
hours,
minutes,
seconds,
};
}
export async function isLoggedIn() {
const user = await getUser();
return !!(user.appwrite || user.github);
const user = await getUser();
return !!(user.appwrite || user.github);
}
export interface GithubUser {
login: string;
name: string;
login: string;
name: string;
}
export async function getGithubUser() {
try {
const { providerAccessToken, provider } = await appwriteInit.account.getSession('current');
if (provider !== 'github') return null;
try {
const { providerAccessToken, provider } =
await appwriteInit.account.getSession("current");
if (provider !== "github") return null;
const res = await fetch('https://api.github.com/user', {
method: 'GET',
headers: {
Authorization: `Bearer ${providerAccessToken}`
}
})
.then((res) => res.json() as Promise<GithubUser>)
.then((n) => ({
login: n.login,
name: n.name
}));
const res = await fetch("https://api.github.com/user", {
method: "GET",
headers: {
Authorization: `Bearer ${providerAccessToken}`,
},
})
.then((res) => res.json() as Promise<GithubUser>)
.then((n) => ({
login: n.login,
name: n.name,
}));
if (!res.login) {
await appwriteInit.account.deleteSession('current');
return null;
}
return res;
} catch (e) {
console.error(e);
return null;
if (!res.login) {
await appwriteInit.account.deleteSession("current");
return null;
}
return res;
} catch (e) {
console.error(e);
return null;
}
}
export type User = {
github: GithubUser | null;
appwrite: AppwriteUser | null;
github: GithubUser | null;
appwrite: AppwriteUser | null;
};
export async function getUser(): Promise<User> {
const [github, appwrite] = await Promise.all([getGithubUser(), getAppwriteUser()]);
const [github, appwrite] = await Promise.all([
getGithubUser(),
getAppwriteUser(),
]);
return { github, appwrite };
return { github, appwrite };
}
export function getMockContributions() {
const result: ContributionsMatrix = [];
for (let i = 0; i < 53; i++) {
result.push([]);
for (let j = 0; j < 7; j++) {
result[i].push(Math.floor(Math.random() * 4));
}
const result: ContributionsMatrix = [];
for (let i = 0; i < 53; i++) {
result.push([]);
for (let j = 0; j < 7; j++) {
result[i].push(Math.floor(Math.random() * 4));
}
return result;
}
return result;
}
export async function getTicketDocByUser(user: User, f = fetch) {
return await f(`/init-0/tickets/get-ticket-doc?user=${JSON.stringify(user)}`).then(
(res) => res.json() as Promise<TicketDoc>
);
return await f(
`/init-0/tickets/get-ticket-doc?user=${JSON.stringify(user)}`,
).then((res) => res.json() as Promise<TicketDoc>);
}
export async function getTicketDocById(id: string, f = fetch) {
return await f(`/init-0/tickets/get-ticket-doc?id=${id}`).then(
(res) => res.json() as Promise<TicketDoc>
);
return await f(`/init-0/tickets/get-ticket-doc?id=${id}`).then(
(res) => res.json() as Promise<TicketDoc>,
);
}
export async function getTicketContributions(id: string, f = fetch): Promise<ContributionsMatrix> {
const res = await f(`/init-0/tickets/${id}/get-contributions`);
const { data: contributions } = (await res
.json()
.then((r) => {
return r;
})
.catch(() => {
return { data: null };
})) as { data: ContributionsMatrix | null };
export async function getTicketContributions(
id: string,
f = fetch,
): Promise<ContributionsMatrix> {
const res = await f(`/init-0/tickets/${id}/get-contributions`);
const { data: contributions } = (await res
.json()
.then((r) => {
return r;
})
.catch(() => {
return { data: null };
})) as { data: ContributionsMatrix | null };
return contributions ?? [];
return contributions ?? [];
}
export function getTicketVariant(
doc: Omit<TicketData, 'contributions' | 'variant'>
doc: Omit<TicketData, "contributions" | "variant">,
): TicketVariant {
const { gh_user, aw_email } = doc;
const { gh_user, aw_email } = doc;
if (gh_user && contributors.includes(gh_user)) {
return 'rainbow';
}
if (gh_user && contributors.includes(gh_user)) {
return "rainbow";
}
if (aw_email) {
return 'pink';
}
if (aw_email) {
return "pink";
}
return 'default';
return "default";
}
export async function getTicketByUser(user: User, f = fetch) {
const doc = await getTicketDocByUser(user, f);
const doc = await getTicketDocByUser(user, f);
const variant = getTicketVariant(doc);
const variant = getTicketVariant(doc);
return {
...doc,
variant
} as TicketData;
return {
...doc,
variant,
} as TicketData;
}
export async function getTicketById(id: string, f = fetch) {
const doc = await getTicketDocById(id, f);
const variant = getTicketVariant(doc);
const doc = await getTicketDocById(id, f);
const variant = getTicketVariant(doc);
return {
...doc,
variant
} as TicketData;
return {
...doc,
variant,
} as TicketData;
}
export function loginGithub() {
appwriteInit.account.createOAuth2Session(
OAuthProvider.Github,
`${window.location.origin}/init-0/tickets?success=1`,
`${window.location.origin}/init-0/tickets?error=1`,
['read:user']
);
appwriteInit.account.createOAuth2Session(
OAuthProvider.Github,
`${window.location.origin}/init-0/tickets?success=1`,
`${window.location.origin}/init-0/tickets?error=1`,
["read:user"],
);
}

View File

@@ -1,49 +1,51 @@
<div class="wrapper">
<slot />
<slot />
</div>
<style lang="scss">
.wrapper {
display: contents;
--p-padding-inline: clamp(1.25rem, 4vw, 120rem);
.wrapper {
display: contents;
--p-padding-inline: clamp(1.25rem, 4vw, 120rem);
:global(.hero) {
display: grid;
grid-template-columns: 1fr min(57%, 770px);
gap: clamp(3rem, 6vw, 7.5rem);
justify-content: space-between;
:global(.hero) {
display: grid;
grid-template-columns: 1fr min(57%, 770px);
gap: clamp(3rem, 6vw, 7.5rem);
justify-content: space-between;
padding-inline: var(--p-padding-inline);
padding-block-start: 4rem;
max-width: 1440px;
margin-inline: auto;
}
@media screen and (max-width: 1023px) {
:global(.hero) {
display: grid;
grid-template-columns: var(--p-padding-inline) 1fr var(--p-padding-inline);
row-gap: 3rem;
column-gap: 0;
padding-block-start: 3rem;
padding-inline: 0;
max-width: 512px;
margin-inline: auto;
> :global(*) {
grid-column: 2;
}
}
:global(.desktop-left) {
/* To put the children in the flex container */
display: contents;
> :global(*) {
grid-column: 2;
}
}
}
padding-inline: var(--p-padding-inline);
padding-block-start: 4rem;
max-width: 1440px;
margin-inline: auto;
}
@media screen and (max-width: 1023px) {
:global(.hero) {
display: grid;
grid-template-columns: var(--p-padding-inline) 1fr var(
--p-padding-inline
);
row-gap: 3rem;
column-gap: 0;
padding-block-start: 3rem;
padding-inline: 0;
max-width: 512px;
margin-inline: auto;
> :global(*) {
grid-column: 2;
}
}
:global(.desktop-left) {
/* To put the children in the flex container */
display: contents;
> :global(*) {
grid-column: 2;
}
}
}
}
</style>

View File

@@ -1,8 +1,8 @@
import { redirect } from '@sveltejs/kit';
import { isLoggedIn } from '../helpers.js';
import { redirect } from "@sveltejs/kit";
import { isLoggedIn } from "../helpers.js";
export const load = async () => {
if (await isLoggedIn()) {
redirect(307, '/init-0/tickets/customize');
}
if (await isLoggedIn()) {
redirect(307, "/init-0/tickets/customize");
}
};

View File

@@ -1,20 +1,23 @@
import { getTicketById, getTicketContributions } from '$routes/init-0/helpers.js';
import { error } from '@sveltejs/kit';
import {
getTicketById,
getTicketContributions,
} from "$routes/init-0/helpers.js";
import { error } from "@sveltejs/kit";
export const ssr = true;
export const load = async ({ params, fetch }) => {
const { id } = params;
try {
const ticket = await getTicketById(id, fetch);
const { id } = params;
try {
const ticket = await getTicketById(id, fetch);
return {
ticket,
streamed: {
contributions: getTicketContributions(ticket.$id, fetch)
}
};
} catch (e) {
error(404, 'Ticket not found');
}
return {
ticket,
streamed: {
contributions: getTicketContributions(ticket.$id, fetch),
},
};
} catch (e) {
error(404, "Ticket not found");
}
};

View File

@@ -1,25 +1,25 @@
import { getContributions } from './helpers.server.js';
import { getContributions } from "./helpers.server.js";
const emptyResponse = new Response(JSON.stringify({ data: null }), {
status: 404,
headers: {
'content-type': 'application/json'
}
status: 404,
headers: {
"content-type": "application/json",
},
});
export async function GET({ params }) {
const matrix = await getContributions(params.id);
if (!matrix) return emptyResponse;
const matrix = await getContributions(params.id);
if (!matrix) return emptyResponse;
return new Response(
JSON.stringify({
data: matrix
}),
{
status: 200,
headers: {
'content-type': 'application/json'
}
}
);
return new Response(
JSON.stringify({
data: matrix,
}),
{
status: 200,
headers: {
"content-type": "application/json",
},
},
);
}

View File

@@ -1,56 +1,64 @@
import { APPWRITE_DB_INIT_ID, APPWRITE_COL_INIT_ID } from '$env/static/private';
import { appwriteInitServer } from '$lib/appwrite/init.server';
import parse from 'node-html-parser';
import type { TicketData, ContributionsMatrix } from '../../constants';
import { APPWRITE_DB_INIT_ID, APPWRITE_COL_INIT_ID } from "$env/static/private";
import { appwriteInitServer } from "$lib/appwrite/init.server";
import parse from "node-html-parser";
import type { TicketData, ContributionsMatrix } from "../../constants";
export async function getContributions(id: string): Promise<ContributionsMatrix | null> {
const { gh_user, contributions } = (await appwriteInitServer.databases.getDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
id
export async function getContributions(
id: string,
): Promise<ContributionsMatrix | null> {
const { gh_user, contributions } =
(await appwriteInitServer.databases.getDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
id,
)) as unknown as TicketData;
if (!gh_user) return null;
if (contributions?.length) {
// Transform flat array into matrix with 7 columns
const matrix: ContributionsMatrix = [];
for (let i = 0; i < contributions.length; i += 7) {
matrix.push(contributions.slice(i, i + 7));
}
return matrix;
}
const res = await fetch(`https://github.com/${gh_user}`);
const html = await res.text();
const root = parse(html);
const table = root.querySelector('table.ContributionCalendar-grid');
if (!table) return null;
if (!gh_user) return null;
if (contributions?.length) {
// Transform flat array into matrix with 7 columns
const matrix: ContributionsMatrix = [];
const rows = table.querySelectorAll('tbody tr');
const maxCols = rows[0].querySelectorAll('[role="gridcell"]').length;
for (let i = 0; i < contributions.length; i += 7) {
matrix.push(contributions.slice(i, i + 7));
}
return matrix;
}
for (let c = 0; c < maxCols; c++) {
matrix.push([]);
for (let r = 0; r < rows.length; r++) {
const row = rows[r];
const cells = row.querySelectorAll('[role="gridcell"]');
if (c >= cells.length) continue;
const res = await fetch(`https://github.com/${gh_user}`);
const cell = cells[c];
matrix[c].push(Number(cell.getAttribute('data-level')));
}
const html = await res.text();
const root = parse(html);
const table = root.querySelector("table.ContributionCalendar-grid");
matrix[c] = matrix[c].reverse();
if (!table) return null;
const matrix: ContributionsMatrix = [];
const rows = table.querySelectorAll("tbody tr");
const maxCols = rows[0].querySelectorAll('[role="gridcell"]').length;
for (let c = 0; c < maxCols; c++) {
matrix.push([]);
for (let r = 0; r < rows.length; r++) {
const row = rows[r];
const cells = row.querySelectorAll('[role="gridcell"]');
if (c >= cells.length) continue;
const cell = cells[c];
matrix[c].push(Number(cell.getAttribute("data-level")));
}
// Update the document with the new contributions
await appwriteInitServer.databases.updateDocument(APPWRITE_DB_INIT_ID, APPWRITE_COL_INIT_ID, id, {
contributions: matrix.flat()
});
matrix[c] = matrix[c].reverse();
}
return matrix;
// Update the document with the new contributions
await appwriteInitServer.databases.updateDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
id,
{
contributions: matrix.flat(),
},
);
return matrix;
}

View File

@@ -1,30 +1,30 @@
import { APPWRITE_COL_INIT_ID, APPWRITE_DB_INIT_ID } from '$env/static/private';
import { appwriteInitServer } from '$lib/appwrite/init.server';
import { getTicketVariant } from '$routes/init-0/helpers';
import sharp from 'sharp';
import type { TicketData } from '../../constants.js';
import { getTicketSvg } from './getTicketSvg.server.js';
import { APPWRITE_COL_INIT_ID, APPWRITE_DB_INIT_ID } from "$env/static/private";
import { appwriteInitServer } from "$lib/appwrite/init.server";
import { getTicketVariant } from "$routes/init-0/helpers";
import sharp from "sharp";
import type { TicketData } from "../../constants.js";
import { getTicketSvg } from "./getTicketSvg.server.js";
export async function GET({ params, fetch }) {
const ticket = (await appwriteInitServer.databases.getDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
params.id
)) as unknown as TicketData;
ticket.variant = getTicketVariant(ticket);
const svg = await getTicketSvg({ ...ticket }, fetch);
const ticket = (await appwriteInitServer.databases.getDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
params.id,
)) as unknown as TicketData;
ticket.variant = getTicketVariant(ticket);
const svg = await getTicketSvg({ ...ticket }, fetch);
const svgBuffer = Buffer.from(svg);
const pngBuffer = await sharp(svgBuffer, {})
.resize({
// width: 1000
})
.toFormat('png')
.toBuffer();
const svgBuffer = Buffer.from(svg);
const pngBuffer = await sharp(svgBuffer, {})
.resize({
// width: 1000
})
.toFormat("png")
.toBuffer();
return new Response(pngBuffer, {
headers: {
'Content-Type': 'image/png'
}
});
return new Response(pngBuffer, {
headers: {
"Content-Type": "image/png",
},
});
}

View File

@@ -1,25 +1,25 @@
import { splitStr } from '$lib/utils/string';
import { splitStr } from "$lib/utils/string";
import type {
ContributionsMatrix,
TicketData,
TicketVariant
} from '$routes/init-0/tickets/constants';
import { getContributions } from '../get-contributions/helpers.server';
ContributionsMatrix,
TicketData,
TicketVariant,
} from "$routes/init-0/tickets/constants";
import { getContributions } from "../get-contributions/helpers.server";
type GetCubeArgs = {
week: number;
day: number;
level: number;
variant?: TicketVariant;
week: number;
day: number;
level: number;
variant?: TicketVariant;
};
const getCube = ({ week, day, level, variant = 'default' }: GetCubeArgs) => {
const x = INITIAL_X + day * DIFF_X;
const y = INITIAL_Y + week * DIFF_Y;
const opacity = level / 4;
const fill = variant === 'rainbow' ? 'white' : '#FD366E';
const getCube = ({ week, day, level, variant = "default" }: GetCubeArgs) => {
const x = INITIAL_X + day * DIFF_X;
const y = INITIAL_Y + week * DIFF_Y;
const opacity = level / 4;
const fill = variant === "rainbow" ? "white" : "#FD366E";
return `<rect opacity="${opacity}" x="${x}" y="${y}" width="3.4087" height="3.4087" rx="0.852174" fill="${fill}" />`;
return `<rect opacity="${opacity}" x="${x}" y="${y}" width="3.4087" height="3.4087" rx="0.852174" fill="${fill}" />`;
};
const INITIAL_X = 380;
const INITIAL_Y = 22.7998;
@@ -27,20 +27,21 @@ const DIFF_Y = 5.1133;
const DIFF_X = 5.1133;
export async function getCubes(ticket: TicketData) {
const matrix = ((await getContributions(ticket.$id)) ?? []) as ContributionsMatrix;
// const matrix = getMockContributions();
const matrix = ((await getContributions(ticket.$id)) ??
[]) as ContributionsMatrix;
// const matrix = getMockContributions();
return matrix.reduce((acc, week, w) => {
week.forEach((level, d) => {
acc.push(getCube({ week: w, day: d, level, variant: ticket.variant }));
});
return matrix.reduce((acc, week, w) => {
week.forEach((level, d) => {
acc.push(getCube({ week: w, day: d, level, variant: ticket.variant }));
});
return acc;
}, [] as string[]);
return acc;
}, [] as string[]);
}
const cards: Record<TicketVariant, string> = {
pink: `<g filter="url(#filter0_b_446_1414)">
pink: `<g filter="url(#filter0_b_446_1414)">
<g clip-path="url(#clip0_446_1414)">
<rect width="438" height="249" rx="18" fill="#19191C"/>
<rect width="438" height="249" rx="18" fill="url(#paint0_linear_446_1414)" fill-opacity="0.64"/>
@@ -76,7 +77,7 @@ const cards: Record<TicketVariant, string> = {
</g>
</g>
</g>`,
default: `<g filter="url(#filter1_b_327_1972)">
default: `<g filter="url(#filter1_b_327_1972)">
<mask id="path-3-inside-1_327_1972" fill="white">
<path fill-rule="evenodd" clip-rule="evenodd"
d="M218.743 26.5222C218 27.9805 218 29.8895 218 33.7076V286.292C218 290.11 218 292.019 218.743 293.477C219.397 294.76 220.44 295.803 221.722 296.457C223.181 297.2 225.09 297.2 228.908 297.2H403.092C406.91 297.2 408.819 297.2 410.278 296.457C411.56 295.803 412.603 294.76 413.257 293.477C414 292.019 414 290.11 414 286.292V33.7076C414 29.8895 414 27.9805 413.257 26.5222C412.603 25.2394 411.56 24.1965 410.278 23.5429C408.819 22.7998 406.91 22.7998 403.092 22.7998H228.908C225.09 22.7998 223.181 22.7998 221.722 23.5429C220.44 24.1965 219.397 25.2394 218.743 26.5222ZM300.661 29.6172C299.72 29.6172 298.957 30.3803 298.957 31.3215C298.957 32.2628 299.72 33.0259 300.661 33.0259H331.339C332.28 33.0259 333.043 32.2628 333.043 31.3215C333.043 30.3803 332.28 29.6172 331.339 29.6172H300.661Z" />
@@ -88,7 +89,7 @@ const cards: Record<TicketVariant, string> = {
d="M218.743 26.5222L218.363 26.3287L218.743 26.5222ZM218.743 293.477L218.363 293.671L218.363 293.671L218.743 293.477ZM221.722 296.457L221.529 296.836L221.529 296.836L221.722 296.457ZM410.278 296.457L410.471 296.836L410.471 296.836L410.278 296.457ZM413.257 293.477L412.877 293.284L412.877 293.284L413.257 293.477ZM413.257 26.5222L412.877 26.7156L412.877 26.7156L413.257 26.5222ZM410.278 23.5429L410.084 23.9225L410.084 23.9225L410.278 23.5429ZM221.722 23.5429L221.529 23.1632L221.722 23.5429ZM218.426 33.7076C218.426 31.7915 218.426 30.3801 218.518 29.2647C218.608 28.1542 218.787 27.3747 219.123 26.7156L218.363 26.3287C217.956 27.128 217.763 28.0321 217.668 29.1953C217.574 30.3535 217.574 31.8056 217.574 33.7076H218.426ZM218.426 286.292V33.7076H217.574V286.292H218.426ZM219.123 293.284C218.787 292.625 218.608 291.845 218.518 290.735C218.426 289.619 218.426 288.208 218.426 286.292H217.574C217.574 288.194 217.574 289.646 217.668 290.804C217.763 291.967 217.956 292.872 218.363 293.671L219.123 293.284ZM221.916 296.077C220.713 295.464 219.735 294.487 219.123 293.284L218.363 293.671C219.058 295.034 220.166 296.142 221.529 296.836L221.916 296.077ZM228.908 296.774C226.992 296.774 225.58 296.773 224.465 296.682C223.354 296.592 222.575 296.413 221.916 296.077L221.529 296.836C222.328 297.244 223.232 297.437 224.395 297.532C225.554 297.626 227.006 297.626 228.908 297.626V296.774ZM403.092 296.774H228.908V297.626H403.092V296.774ZM410.084 296.077C409.425 296.413 408.646 296.592 407.535 296.682C406.42 296.773 405.008 296.774 403.092 296.774V297.626C404.994 297.626 406.446 297.626 407.605 297.532C408.768 297.437 409.672 297.244 410.471 296.836L410.084 296.077ZM412.877 293.284C412.265 294.487 411.287 295.464 410.084 296.077L410.471 296.836C411.834 296.142 412.942 295.034 413.637 293.671L412.877 293.284ZM413.574 286.292C413.574 288.208 413.574 289.619 413.482 290.735C413.392 291.845 413.213 292.625 412.877 293.284L413.637 293.671C414.044 292.872 414.237 291.967 414.332 290.804C414.426 289.646 414.426 288.194 414.426 286.292H413.574ZM413.574 33.7076V286.292H414.426V33.7076H413.574ZM412.877 26.7156C413.213 27.3747 413.392 28.1542 413.482 29.2647C413.574 30.3801 413.574 31.7916 413.574 33.7076H414.426C414.426 31.8056 414.426 30.3535 414.332 29.1953C414.237 28.0321 414.044 27.128 413.637 26.3287L412.877 26.7156ZM410.084 23.9225C411.287 24.5353 412.265 25.513 412.877 26.7156L413.637 26.3287C412.942 24.9658 411.834 23.8577 410.471 23.1632L410.084 23.9225ZM403.092 23.2259C405.008 23.2259 406.42 23.2262 407.535 23.3174C408.646 23.4081 409.425 23.5867 410.084 23.9225L410.471 23.1632C409.672 22.756 408.768 22.563 407.605 22.468C406.446 22.3734 404.994 22.3737 403.092 22.3737V23.2259ZM228.908 23.2259H403.092V22.3737H228.908V23.2259ZM221.916 23.9225C222.575 23.5867 223.354 23.4081 224.465 23.3174C225.58 23.2262 226.992 23.2259 228.908 23.2259V22.3737C227.006 22.3737 225.554 22.3734 224.395 22.468C223.232 22.563 222.328 22.756 221.529 23.1632L221.916 23.9225ZM219.123 26.7156C219.735 25.513 220.713 24.5353 221.916 23.9225L221.529 23.1632C220.166 23.8577 219.058 24.9658 218.363 26.3287L219.123 26.7156ZM299.383 31.3215C299.383 30.6156 299.955 30.0433 300.661 30.0433V29.1911C299.484 29.1911 298.53 30.1449 298.53 31.3215H299.383ZM300.661 32.5998C299.955 32.5998 299.383 32.0275 299.383 31.3215H298.53C298.53 32.4981 299.484 33.452 300.661 33.452V32.5998ZM331.339 32.5998H300.661V33.452H331.339V32.5998ZM332.617 31.3215C332.617 32.0275 332.045 32.5998 331.339 32.5998V33.452C332.516 33.452 333.47 32.4981 333.47 31.3215H332.617ZM331.339 30.0433C332.045 30.0433 332.617 30.6156 332.617 31.3215H333.47C333.47 30.1449 332.516 29.1911 331.339 29.1911V30.0433ZM300.661 30.0433H331.339V29.1911H300.661V30.0433Z"
fill="url(#paint2_linear_327_1972)" fill-opacity="0.32" mask="url(#path-3-inside-1_327_1972)" />
</g>`,
rainbow: `<g xmlns="http://www.w3.org/2000/svg" filter="url(#filter0_b_450_3173)">
rainbow: `<g xmlns="http://www.w3.org/2000/svg" filter="url(#filter0_b_450_3173)">
<g clip-path="url(#clip0_450_3173)">
<rect width="438" height="249" rx="18" fill="#19191C"/>
<rect width="438" height="249" rx="18" fill="url(#paint0_linear_450_3173)" fill-opacity="0.64"/>
@@ -99,50 +100,53 @@ const cards: Record<TicketVariant, string> = {
<rect x="177" y="-15" width="277" height="354" fill="url(#pattern0)"/>
<rect x="214.791" y="143" width="222.857" height="106.297" fill="url(#paint2_linear_450_3173)"/>
</g>
</g>`
</g>`,
};
function getTribeSource(variant: TicketVariant, tribe: string) {
if (variant === 'rainbow') {
return `/images/tribes/rainbow/${tribe?.toLowerCase()}.png`;
}
return `/images/tribes/${tribe?.toLowerCase()}.png`;
if (variant === "rainbow") {
return `/images/tribes/rainbow/${tribe?.toLowerCase()}.png`;
}
return `/images/tribes/${tribe?.toLowerCase()}.png`;
}
async function toBase64(src: string, f: typeof fetch) {
const base64 = await f(src)
.then((res) => res.arrayBuffer())
.then((buf) => Buffer.from(buf).toString('base64'));
const img_type = src.split('.').pop();
const base64 = await f(src)
.then((res) => res.arrayBuffer())
.then((buf) => Buffer.from(buf).toString("base64"));
const img_type = src.split(".").pop();
return `data:image/${img_type === 'svg' ? 'svg+xml' : img_type};base64,${base64}`;
return `data:image/${img_type === "svg" ? "svg+xml" : img_type};base64,${base64}`;
}
export const getTicketSvg = async (ticket: TicketData, f: typeof fetch) => {
const cubes = await getCubes(ticket);
const cubes = await getCubes(ticket);
const line_height = 18;
const big_line_height = 22;
const chars_per_line = 16;
// split ticket name in max 16 chars per line
const split_name = splitStr(ticket.name, { chars: chars_per_line, breakWord: false });
const line_height = 18;
const big_line_height = 22;
const chars_per_line = 16;
// split ticket name in max 16 chars per line
const split_name = splitStr(ticket.name, {
chars: chars_per_line,
breakWord: false,
});
const rainbow_png = await toBase64('/images/tickets/rainbow.png', f);
const rainbow_png = await toBase64("/images/tickets/rainbow.png", f);
let tribe_svg: string | undefined = undefined;
if (ticket.tribe) {
const tribe_src = getTribeSource(ticket.variant ?? 'default', ticket.tribe);
tribe_svg = await toBase64(tribe_src, f);
}
let tribe_svg: string | undefined = undefined;
if (ticket.tribe) {
const tribe_src = getTribeSource(ticket.variant ?? "default", ticket.tribe);
tribe_svg = await toBase64(tribe_src, f);
}
return `
return `
<svg width="876" height="498" viewBox="0 0 438 249" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_b_327_1972)">
<g >
<rect width="438" height="249" fill="#19191C" />
<rect width="438" height="249" fill="url(#paint0_linear_327_1972)" fill-opacity="0.64" />
<g clip-path="url(#clip1_327_1972)">
${cards[ticket.variant ?? 'default']}
${cards[ticket.variant ?? "default"]}
<g filter="url(#filter2_f_327_1972)">
<path
d="M350.938 32.9374L187.966 224.365C176.667 237.637 177.096 257.267 188.966 270.033C202.592 284.688 225.811 284.643 239.38 269.935L409.852 85.1547C425.723 67.952 423.17 40.7847 404.372 26.8396C387.731 14.4945 364.37 17.1604 350.938 32.9374Z"
@@ -159,31 +163,31 @@ export const getTicketSvg = async (ticket: TicketData, f: typeof fetch) => {
fill="url(#paint5_linear_327_1972)" />
</mask>
<g mask="url(#mask1_327_1972)">
${cubes.join('')}
${cubes.join("")}
</g>
</g>
${
ticket.gh_user
? `
ticket.gh_user
? `
<text transform="translate(232.061 67.1128)" fill="#ADADB0" xml:space="preserve" style="white-space: pre"
font-family="Aeonik Pro" font-size="10.2261" letter-spacing="0em">
<tspan x="0" y="${9.69774 + line_height * (split_name.length - 1)}">@${ticket.gh_user}</tspan>
</text>
`
: ''
: ""
}
${split_name.map(
(line, i) => `
(line, i) => `
<text transform="translate(232.061 46.6606)" fill="white" xml:space="preserve" style="white-space: pre"
font-family="Aeonik Pro" font-size="17.0435" letter-spacing="-0.01em">
<tspan x="0" y="${15.5 + line_height * i}">${line}</tspan>
</text>
`
`,
)}
${
tribe_svg
? `<image x="160" y="130" width="200" height="200" xlink:href="${tribe_svg}" xmlns:xlink="http://www.w3.org/1999/xlink"/>`
: ''
tribe_svg
? `<image x="160" y="130" width="200" height="200" xlink:href="${tribe_svg}" xmlns:xlink="http://www.w3.org/1999/xlink"/>`
: ""
}
</g>
@@ -196,12 +200,12 @@ export const getTicketSvg = async (ticket: TicketData, f: typeof fetch) => {
<tspan x="20.5273" y="${71.2692 + big_line_height * (split_name.length - 1)}">init</tspan>
</text>
${split_name.map(
(line, i) => `
(line, i) => `
<text fill="white" fill-opacity="0.64" xml:space="preserve" style="white-space: pre" font-family="Aeonik Pro"
font-size="23.7885" letter-spacing="-0.01em">
<tspan x="20.5273" y="${44.8783 + big_line_height * i}">${line}</tspan>
</text>
`
`,
)}
<path
@@ -237,8 +241,8 @@ export const getTicketSvg = async (ticket: TicketData, f: typeof fetch) => {
<text transform="translate(20.9619 84.6782)" fill="white" fill-opacity="0.5" xml:space="preserve"
style="white-space: pre" font-family="Aeonik Fono" font-size="10.2656" letter-spacing="0em">
<tspan x="0" y="${8.74695 + big_line_height * (split_name.length - 1)}">#${ticket.id
.toString()
.padStart(6, '0')}</tspan>
.toString()
.padStart(6, "0")}</tspan>
</text>
<rect x="214.791" y="143" width="222.857" height="106.297" fill="url(#paint7_linear_327_1972)" />
</g>

View File

@@ -1,25 +1,25 @@
import { invalidate } from '$app/navigation';
import type { Models } from '@appwrite.io/console';
import { invalidate } from "$app/navigation";
import type { Models } from "@appwrite.io/console";
export const TICKET_DEP = 'ticket';
export const TICKET_DEP = "ticket";
export const invalidateTicket = () => {
invalidate(TICKET_DEP);
invalidate(TICKET_DEP);
};
export type ContributionsMatrix = number[][];
export type TicketVariant = 'default' | 'pink' | 'rainbow';
export type TicketVariant = "default" | "pink" | "rainbow";
export type TicketData = Pick<Models.Document, '$id'> & {
name: string;
tribe?: string | null
gh_user?: string;
aw_email?: string;
id: number;
show_contributions?: boolean;
variant?: TicketVariant;
is_pro?: boolean;
contributions?: number[];
export type TicketData = Pick<Models.Document, "$id"> & {
name: string;
tribe?: string | null;
gh_user?: string;
aw_email?: string;
id: number;
show_contributions?: boolean;
variant?: TicketVariant;
is_pro?: boolean;
contributions?: number[];
};
export type TicketDoc = Omit<TicketData, 'contributions' | 'variant'>;
export type TicketDoc = Omit<TicketData, "contributions" | "variant">;

View File

@@ -1,25 +1,25 @@
import {
getTicketByUser,
getTicketContributions,
getUser,
isLoggedIn
} from '$routes/init-0/helpers';
import { redirect } from '@sveltejs/kit';
getTicketByUser,
getTicketContributions,
getUser,
isLoggedIn,
} from "$routes/init-0/helpers";
import { redirect } from "@sveltejs/kit";
export const load = async () => {
const loggedIn = await isLoggedIn();
if (!loggedIn) {
redirect(307, '/init-0/tickets');
}
const loggedIn = await isLoggedIn();
if (!loggedIn) {
redirect(307, "/init-0/tickets");
}
const user = await getUser();
const ticket = await getTicketByUser(user);
const user = await getUser();
const ticket = await getTicketByUser(user);
return {
ticket,
user,
streamed: {
contributions: getTicketContributions(ticket.$id, fetch)
}
};
return {
ticket,
user,
streamed: {
contributions: getTicketContributions(ticket.$id, fetch),
},
};
};

View File

@@ -1,181 +1,189 @@
<script lang="ts" context="module">
export const tribes = [
null,
'Appwrite',
'Flutter',
'Svelte',
'React',
'Vue',
'Angular',
'Next',
'Astro',
'Qwik',
'Apple',
'Android',
'Windows',
'Linux',
'Python',
'Dart',
'php',
'Ruby',
'NET'
];
export const tribes = [
null,
"Appwrite",
"Flutter",
"Svelte",
"React",
"Vue",
"Angular",
"Next",
"Astro",
"Qwik",
"Apple",
"Android",
"Windows",
"Linux",
"Python",
"Dart",
"php",
"Ruby",
"NET",
];
</script>
<script lang="ts">
import { browser, dev } from '$app/environment';
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { PUBLIC_APPWRITE_DASHBOARD } from '$env/static/public';
import { appwriteInit } from '$lib/appwrite/init';
import { Switch } from '$lib/components';
import { loginGithub } from '$routes/init-0/helpers';
import type { TicketVariant } from '../constants';
import { browser, dev } from "$app/environment";
import { goto } from "$app/navigation";
import { page } from "$app/stores";
import { PUBLIC_APPWRITE_DASHBOARD } from "$env/static/public";
import { appwriteInit } from "$lib/appwrite/init";
import { Switch } from "$lib/components";
import { loginGithub } from "$routes/init-0/helpers";
import type { TicketVariant } from "../constants";
import type { PageData } from './$types';
import TribeToggle from './tribe-toggle.svelte';
import type { PageData } from "./$types";
import TribeToggle from "./tribe-toggle.svelte";
export let name = '';
export let tribe: string | null = null;
export let showGitHub = true;
export let variant: TicketVariant = 'default';
$: ({ ticket } = $page.data as PageData);
export let name = "";
export let tribe: string | null = null;
export let showGitHub = true;
export let variant: TicketVariant = "default";
$: ({ ticket } = $page.data as PageData);
const variants: TicketVariant[] = ['default', 'pink', 'rainbow'] as const;
const variants: TicketVariant[] = ["default", "pink", "rainbow"] as const;
</script>
<div class="u-flex u-flex-vertical u-gap-4 u-margin-block-start-32">
<label for="name">Your name</label>
<input
class="web-input-text"
type="text"
placeholder="Enter your name"
id="name"
name="name"
required
bind:value={name}
maxlength="42"
disabled={!browser}
/>
<label for="name">Your name</label>
<input
class="web-input-text"
type="text"
placeholder="Enter your name"
id="name"
name="name"
required
bind:value={name}
maxlength="42"
disabled={!browser}
/>
</div>
{#if dev}
<label for="variant" class="u-margin-block-start-32 u-block">Ticket variant (DEBUG)</label>
<select
id="variant"
class="u-margin-block-start-4"
style:text-transform="capitalize"
bind:value={variant}
>
{#each variants as variant}
<option value={variant}>{variant}</option>
{/each}
</select>
<label for="variant" class="u-margin-block-start-32 u-block"
>Ticket variant (DEBUG)</label
>
<select
id="variant"
class="u-margin-block-start-4"
style:text-transform="capitalize"
bind:value={variant}
>
{#each variants as variant}
<option value={variant}>{variant}</option>
{/each}
</select>
{/if}
<hr />
{#if ticket.gh_user}
<div class="u-flex u-cross-center u-gap-8 web-u-color-text-primary">
<img src="/images/icons/colored/check.svg" alt="" />
<span class="web-sub-body-500">GitHub account connected</span>
</div>
<div class="u-flex u-cross-center u-gap-8 web-u-color-text-primary">
<img src="/images/icons/colored/check.svg" alt="" />
<span class="web-sub-body-500">GitHub account connected</span>
</div>
<div
class="u-flex u-cross-center u-main-between"
style="margin-block-start: 0.25rem; gap: 1.25rem"
>
<p class="web-sub-body-500">
Your ticket has been updated to show your unique GitHub contribution pattern.
</p>
<Switch bind:checked={showGitHub} />
</div>
{#if dev}
<button
class="web-button is-full-width is-secondary u-margin-block-start-24"
on:click={async () => {
await appwriteInit.account.deleteSession('current');
goto('/init-0/tickets');
}}
disabled={!browser}
>
<div class="web-icon-github web-u-color-text-primary" />
<span class="text">(DEBUG) Log-out of GitHub</span>
</button>
{/if}
{:else}
<h2 class="web-sub-body-500 web-u-color-text-primary">Integrate your GitHub account</h2>
<p class="web-sub-body-500" style:margin-block-start="0.25rem">
Sign in with your GitHub account and see the magic happen in your ticket.
<div
class="u-flex u-cross-center u-main-between"
style="margin-block-start: 0.25rem; gap: 1.25rem"
>
<p class="web-sub-body-500">
Your ticket has been updated to show your unique GitHub contribution
pattern.
</p>
<Switch bind:checked={showGitHub} />
</div>
{#if dev}
<button
class="web-button is-full-width is-secondary u-margin-block-start-24"
on:click={loginGithub}
class="web-button is-full-width is-secondary u-margin-block-start-24"
on:click={async () => {
await appwriteInit.account.deleteSession("current");
goto("/init-0/tickets");
}}
disabled={!browser}
>
<div class="web-icon-github web-u-color-text-primary" />
<span class="text">Log in to GitHub account</span>
<div class="web-icon-github web-u-color-text-primary" />
<span class="text">(DEBUG) Log-out of GitHub</span>
</button>
{/if}
{:else}
<h2 class="web-sub-body-500 web-u-color-text-primary">
Integrate your GitHub account
</h2>
<p class="web-sub-body-500" style:margin-block-start="0.25rem">
Sign in with your GitHub account and see the magic happen in your ticket.
</p>
<button
class="web-button is-full-width is-secondary u-margin-block-start-24"
on:click={loginGithub}
>
<div class="web-icon-github web-u-color-text-primary" />
<span class="text">Log in to GitHub account</span>
</button>
{/if}
<hr />
{#if ticket.aw_email}
<div class="u-flex u-cross-center u-gap-8 web-u-color-text-primary">
<img src="/images/icons/colored/check.svg" alt="" />
<span class="web-sub-body-500">Appwrite account connected</span>
</div>
<div class="u-flex u-cross-center u-gap-8 web-u-color-text-primary">
<img src="/images/icons/colored/check.svg" alt="" />
<span class="web-sub-body-500">Appwrite account connected</span>
</div>
<p class="web-sub-body-500" style="margin-block-start: 0.25rem;">
Your ticket has been upgraded.
</p>
<p class="web-sub-body-500" style="margin-block-start: 0.25rem;">
Your ticket has been upgraded.
</p>
{:else}
<h2 class="web-sub-body-500 web-u-color-text-primary">Integrate your Appwrite account</h2>
<p class="web-sub-body-500" style:margin-block-start="0.25rem">
Sign in with your Appwrite account and see the magic happen in your ticket.
</p>
<a
href="{PUBLIC_APPWRITE_DASHBOARD}/login?forceRedirect={$page.url.origin}/init-0/tickets"
class="web-button is-full-width is-secondary u-margin-block-start-24"
>
<div class="web-icon-appwrite web-u-color-text-primary" />
<span class="text">Log in to Appwrite account</span>
</a>
<h2 class="web-sub-body-500 web-u-color-text-primary">
Integrate your Appwrite account
</h2>
<p class="web-sub-body-500" style:margin-block-start="0.25rem">
Sign in with your Appwrite account and see the magic happen in your ticket.
</p>
<a
href="{PUBLIC_APPWRITE_DASHBOARD}/login?forceRedirect={$page.url
.origin}/init-0/tickets"
class="web-button is-full-width is-secondary u-margin-block-start-24"
>
<div class="web-icon-appwrite web-u-color-text-primary" />
<span class="text">Log in to Appwrite account</span>
</a>
{/if}
<hr />
<h2 class="web-sub-body-500 web-u-color-text-primary">Add your tribe</h2>
<p class="web-sub-body-500" style:margin-block-start="0.25rem">
Customize your Init ticket with your technology.
Customize your Init ticket with your technology.
</p>
<div class="tribes">
{#each tribes as t}
<TribeToggle
tribe={t}
checked={t === tribe}
onClick={() => {
tribe = t;
}}
/>
{/each}
{#each tribes as t}
<TribeToggle
tribe={t}
checked={t === tribe}
onClick={() => {
tribe = t;
}}
/>
{/each}
</div>
<style lang="scss">
hr {
margin-block: 2rem;
border-block-end: 1px solid hsl(var(--web-color-offset));
}
hr {
margin-block: 2rem;
border-block-end: 1px solid hsl(var(--web-color-offset));
}
.tribes {
margin-block-start: 1.5rem;
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
@media (max-width: 1023px) {
.tribes {
margin-block-start: 1.5rem;
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
@media (max-width: 1023px) {
.tribes {
gap: 0.625rem;
}
gap: 0.625rem;
}
}
</style>

View File

@@ -1,56 +1,56 @@
<script lang="ts">
import { browser } from '$app/environment';
import Tooltip from '$lib/components/Tooltip.svelte';
import { createCheckbox, melt } from '@melt-ui/svelte';
import { browser } from "$app/environment";
import Tooltip from "$lib/components/Tooltip.svelte";
import { createCheckbox, melt } from "@melt-ui/svelte";
export let checked = false;
export let onClick: () => void;
export let tribe: string | null;
export let checked = false;
export let onClick: () => void;
export let tribe: string | null;
const {
elements: { root },
states: { checked: localChecked }
} = createCheckbox({
name: 'tribe'
});
const {
elements: { root },
states: { checked: localChecked },
} = createCheckbox({
name: "tribe",
});
$: localChecked.set(checked);
$: localChecked.set(checked);
$: src = `/images/tribes/${tribe === null ? 'stop' : tribe.toLowerCase()}.svg`;
$: alt = tribe === null ? 'No tribe' : tribe;
$: src = `/images/tribes/${tribe === null ? "stop" : tribe.toLowerCase()}.svg`;
$: alt = tribe === null ? "No tribe" : tribe;
</script>
<Tooltip disableHoverableContent>
<button
class="web-icon-button web-box-icon has-border-gradient"
use:melt={$root}
on:m-click|preventDefault={onClick}
disabled={!browser}
>
<img {src} {alt} />
</button>
<svelte:fragment slot="tooltip">{alt}</svelte:fragment>
<button
class="web-icon-button web-box-icon has-border-gradient"
use:melt={$root}
on:m-click|preventDefault={onClick}
disabled={!browser}
>
<img {src} {alt} />
</button>
<svelte:fragment slot="tooltip">{alt}</svelte:fragment>
</Tooltip>
<style lang="scss">
button {
width: 3.5rem;
height: 3.5rem;
button {
width: 3.5rem;
height: 3.5rem;
display: grid;
place-items: center;
display: grid;
place-items: center;
&:not(:hover):not(:active) {
background: hsl(var(--web-color-card));
}
&:not(:hover):not(:active) {
background: hsl(var(--web-color-card));
}
}
:global([data-state='checked']):is(button) {
--m-border-gradient-before: white;
}
:global([data-state="checked"]):is(button) {
--m-border-gradient-before: white;
}
:global([data-state='checked']):is(button) img {
/* Filter to white */
filter: brightness(0) invert(1);
}
:global([data-state="checked"]):is(button) img {
/* Filter to white */
filter: brightness(0) invert(1);
}
</style>

View File

@@ -1,155 +1,155 @@
import { APPWRITE_COL_INIT_ID, APPWRITE_DB_INIT_ID } from '$env/static/private';
import { appwriteInitServer } from '$lib/appwrite/init.server';
import { isProUser } from '$lib/utils/console.js';
import type { User } from '$routes/init-0/helpers.js';
import { ID, Query } from '@appwrite.io/console';
import type { TicketData, TicketDoc } from '../constants.js';
import { APPWRITE_COL_INIT_ID, APPWRITE_DB_INIT_ID } from "$env/static/private";
import { appwriteInitServer } from "$lib/appwrite/init.server";
import { isProUser } from "$lib/utils/console.js";
import type { User } from "$routes/init-0/helpers.js";
import { ID, Query } from "@appwrite.io/console";
import type { TicketData, TicketDoc } from "../constants.js";
type SendToHubspotArgs = {
name: string;
email: string;
name: string;
email: string;
};
async function sendToHubspot({ name, email }: SendToHubspotArgs) {
await fetch('https://growth.appwrite.io/v1/mailinglists/init', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email,
name
})
});
await fetch("https://growth.appwrite.io/v1/mailinglists/init", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
name,
}),
});
}
async function getTicketDocByUser(user: User) {
if (user.appwrite?.email) {
sendToHubspot({
name: user.appwrite?.name ?? user.github?.name ?? user.appwrite.email,
email: user.appwrite?.email
});
if (user.appwrite?.email) {
sendToHubspot({
name: user.appwrite?.name ?? user.github?.name ?? user.appwrite.email,
email: user.appwrite?.email,
});
}
const [gh, aw, isPro] = await Promise.all([
user.github?.login
? appwriteInitServer.databases.listDocuments(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
[Query.equal("gh_user", user.github.login)],
)
: null,
user.appwrite?.$id
? appwriteInitServer.databases.listDocuments(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
[Query.equal("aw_email", user.appwrite.email)],
)
: null,
isProUser(),
]);
if (gh?.total || aw?.total) {
const gh_doc = gh?.documents[0] as unknown as TicketDoc;
const aw_doc = aw?.documents[0] as unknown as TicketDoc;
// If both documents exist, and they are not the same, delete the oldest one
if (gh_doc && aw_doc && gh_doc.$id !== aw_doc.$id) {
const oldest = gh_doc.id < aw_doc.id ? gh_doc.$id : aw_doc.$id;
const newest = gh_doc.id > aw_doc.id ? gh_doc.$id : aw_doc.$id;
await appwriteInitServer.databases.updateDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
oldest,
{
gh_user: null,
aw_email: null,
},
);
return (await appwriteInitServer.databases.updateDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
newest,
{
gh_user: user.github?.login,
aw_email: user.appwrite?.email,
},
)) as unknown as TicketDoc;
}
const [gh, aw, isPro] = await Promise.all([
user.github?.login
? appwriteInitServer.databases.listDocuments(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
[Query.equal('gh_user', user.github.login)]
)
: null,
user.appwrite?.$id
? appwriteInitServer.databases.listDocuments(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
[Query.equal('aw_email', user.appwrite.email)]
)
: null,
isProUser()
]);
const doc = gh_doc ?? aw_doc;
if (gh?.total || aw?.total) {
const gh_doc = gh?.documents[0] as unknown as TicketDoc;
const aw_doc = aw?.documents[0] as unknown as TicketDoc;
// If both documents exist, and they are not the same, delete the oldest one
if (gh_doc && aw_doc && gh_doc.$id !== aw_doc.$id) {
const oldest = gh_doc.id < aw_doc.id ? gh_doc.$id : aw_doc.$id;
const newest = gh_doc.id > aw_doc.id ? gh_doc.$id : aw_doc.$id;
await appwriteInitServer.databases.updateDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
oldest,
{
gh_user: null,
aw_email: null
}
);
return (await appwriteInitServer.databases.updateDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
newest,
{
gh_user: user.github?.login,
aw_email: user.appwrite?.email
}
)) as unknown as TicketDoc;
}
const doc = gh_doc ?? aw_doc;
// If the document is missing either the GitHub or Appwrite user, update it
if (!doc.gh_user || !doc.aw_email) {
return (await appwriteInitServer.databases.updateDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
doc.$id,
{
gh_user: user.github?.login,
aw_email: user.appwrite?.email
}
)) as unknown as TicketDoc;
}
// If the user's pro status has changed, update the document
if (!!user.appwrite && doc.is_pro !== isPro) {
return (await appwriteInitServer.databases.updateDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
doc.$id,
{
is_pro: isPro
}
)) as unknown as TicketDoc;
}
// Otherwise, return the document as is
return doc;
} else {
// If no document exists, create one
const allDocs = await appwriteInitServer.databases.listDocuments(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID
);
return (await appwriteInitServer.databases.createDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
ID.unique(),
{
gh_user: user.github?.login ?? undefined,
aw_email: user.appwrite?.email ?? undefined,
id: allDocs.total + 1,
name: user.appwrite?.name ?? user.github?.name,
is_pro: isPro
}
)) as unknown as TicketDoc;
// If the document is missing either the GitHub or Appwrite user, update it
if (!doc.gh_user || !doc.aw_email) {
return (await appwriteInitServer.databases.updateDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
doc.$id,
{
gh_user: user.github?.login,
aw_email: user.appwrite?.email,
},
)) as unknown as TicketDoc;
}
// If the user's pro status has changed, update the document
if (!!user.appwrite && doc.is_pro !== isPro) {
return (await appwriteInitServer.databases.updateDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
doc.$id,
{
is_pro: isPro,
},
)) as unknown as TicketDoc;
}
// Otherwise, return the document as is
return doc;
} else {
// If no document exists, create one
const allDocs = await appwriteInitServer.databases.listDocuments(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
);
return (await appwriteInitServer.databases.createDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
ID.unique(),
{
gh_user: user.github?.login ?? undefined,
aw_email: user.appwrite?.email ?? undefined,
id: allDocs.total + 1,
name: user.appwrite?.name ?? user.github?.name,
is_pro: isPro,
},
)) as unknown as TicketDoc;
}
}
async function getTicketDocById(id: string) {
return (await appwriteInitServer.databases.getDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
id
)) as unknown as Omit<TicketData, 'contributions' | 'variant'>;
return (await appwriteInitServer.databases.getDocument(
APPWRITE_DB_INIT_ID,
APPWRITE_COL_INIT_ID,
id,
)) as unknown as Omit<TicketData, "contributions" | "variant">;
}
export async function GET({ url }) {
if (url.searchParams.has('id')) {
const res = await getTicketDocById(url.searchParams.get('id') ?? '');
return new Response(JSON.stringify(res), {
headers: {
'content-type': 'application/json'
}
});
} else {
const user = JSON.parse(url.searchParams.get('user') ?? '{}') as User;
const res = await getTicketDocByUser(user);
return new Response(JSON.stringify(res), {
headers: {
'content-type': 'application/json'
}
});
}
if (url.searchParams.has("id")) {
const res = await getTicketDocById(url.searchParams.get("id") ?? "");
return new Response(JSON.stringify(res), {
headers: {
"content-type": "application/json",
},
});
} else {
const user = JSON.parse(url.searchParams.get("user") ?? "{}") as User;
const res = await getTicketDocByUser(user);
return new Response(JSON.stringify(res), {
headers: {
"content-type": "application/json",
},
});
}
}

View File

@@ -1,8 +1,8 @@
import { APPWRITE_COL_INIT_ID, APPWRITE_DB_INIT_ID } from '$env/static/private';
import { appwriteInitServer } from '$lib/appwrite/init.server';
import { APPWRITE_COL_INIT_ID, APPWRITE_DB_INIT_ID } from "$env/static/private";
import { appwriteInitServer } from "$lib/appwrite/init.server";
export async function POST({ request }) {
const data = await request.json()
const data = await request.json();
await appwriteInitServer.databases.updateDocument(
APPWRITE_DB_INIT_ID,
@@ -11,20 +11,19 @@ export async function POST({ request }) {
{
name: data.name,
tribe: data.tribe,
show_contributions: data.showGitHub
}
show_contributions: data.showGitHub,
},
);
return new Response(
JSON.stringify({
data: null
data: null,
}),
{
status: 200,
headers: {
'content-type': 'application/json'
}
}
"content-type": "application/json",
},
},
);
}
}

View File

@@ -7,14 +7,14 @@
*/
.hljs {
background: #2b2b2b;
color: #f8f8f2;
background: #2b2b2b;
color: #f8f8f2;
}
/* Comment */
.hljs-comment,
.hljs-quote {
color: #d4d0ab;
color: #d4d0ab;
}
/* Red */
@@ -26,7 +26,7 @@
.hljs-selector-class,
.hljs-regexp,
.hljs-deletion {
color: #ffa07a;
color: #ffa07a;
}
/* Orange */
@@ -37,12 +37,12 @@
.hljs-params,
.hljs-meta,
.hljs-link {
color: #f5ab35;
color: #f5ab35;
}
/* Yellow */
.hljs-attribute {
color: #ffd700;
color: #ffd700;
}
/* Green */
@@ -50,69 +50,69 @@
.hljs-symbol,
.hljs-bullet,
.hljs-addition {
color: #abe338;
color: #abe338;
}
/* Blue */
.hljs-title,
.hljs-section {
color: #00e0e0;
color: #00e0e0;
}
/* Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #dcc6e0;
color: #dcc6e0;
}
.hljs-emphasis {
font-style: italic;
font-style: italic;
}
.hljs-strong {
font-weight: bold;
font-weight: bold;
}
@media screen and (-ms-high-contrast: active) {
.hljs-addition,
.hljs-attribute,
.hljs-built_in,
.hljs-bullet,
.hljs-comment,
.hljs-link,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-params,
.hljs-string,
.hljs-symbol,
.hljs-type,
.hljs-quote {
color: highlight;
}
.hljs-addition,
.hljs-attribute,
.hljs-built_in,
.hljs-bullet,
.hljs-comment,
.hljs-link,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-params,
.hljs-string,
.hljs-symbol,
.hljs-type,
.hljs-quote {
color: highlight;
}
.hljs-keyword,
.hljs-selector-tag {
font-weight: bold;
}
.hljs-keyword,
.hljs-selector-tag {
font-weight: bold;
}
}
/* Our Overrides */
pre {
color: #e4e4e7;
color: #e4e4e7;
}
code.line-numbers .line {
counter-increment: line;
counter-increment: line;
}
code.line-numbers .line:before {
content: counter(line);
display: inline-block;
text-align: right;
padding-right: 1rem;
color: #6c6c71;
width: 2.5rem;
content: counter(line);
display: inline-block;
text-align: right;
padding-right: 1rem;
color: #6c6c71;
width: 2.5rem;
}
.hljs-doctag,
@@ -122,7 +122,7 @@ code.line-numbers .line:before {
.hljs-template-variable,
.hljs-type,
.hljs-variable.language_ {
color: #fe86a8;
color: #fe86a8;
}
.hljs-title,
@@ -130,7 +130,7 @@ code.line-numbers .line:before {
.hljs-title.class_.inherited__,
.hljs-title.function_,
.hljs-symbol {
color: #68a3fe;
color: #68a3fe;
}
.hljs-attr,
@@ -144,25 +144,25 @@ code.line-numbers .line:before {
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id {
color: #fe9567;
color: #fe9567;
}
.hljs-regexp,
.hljs-string,
.hljs-meta .hljs-string {
color: #85dbd8;
color: #85dbd8;
}
.hljs-comment,
.hljs-code,
.hljs-formula {
color: #adadb0;
color: #adadb0;
}
.hljs-emphasis {
font-style: italic;
font-style: italic;
}
.hljs-strong {
font-weight: bold;
font-weight: bold;
}