phone cmp

This commit is contained in:
tglide
2023-09-11 16:35:38 +01:00
parent 2797c1176c
commit c8c97a51ab
10 changed files with 329 additions and 96 deletions

View File

@@ -97,15 +97,15 @@
id="open-source"
use:scroll
on:aw-scroll={({ detail }) => {
const { scrollPercentage } = detail;
scrollHandler(scrollPercentage);
const { percentage } = detail;
scrollHandler(percentage);
}}
on:aw-resize={({ detail }) => {
scrollHandler.reset();
const { scrollPercentage } = detail;
console.log('resize', scrollPercentage);
const { percentage } = detail;
console.log('resize', percentage);
scrollHandler(scrollPercentage);
scrollHandler(percentage);
}}
>
<div class="sticky-wrapper">

View File

@@ -0,0 +1,197 @@
<script lang="ts">
import { toScale, type Scale } from '$lib/utils/toScale';
import { spring, type AnimationListOptions, type SpringOptions } from 'motion';
import { animation, createScrollHandler, scroll, type Animation, type ScrollInfo } from '.';
import { fly, slide } from 'svelte/transition';
import { Phone } from '$lib/components';
const springOptions: SpringOptions = { stiffness: 58.78, mass: 1, damping: 17.14 };
const animationOptions: AnimationListOptions = {
x: { easing: spring(springOptions) },
y: { easing: spring(springOptions) }
};
const animations: {
mobile: {
main: Animation;
reversed: Animation;
};
desktop: {
main: Animation;
reversed: Animation;
};
}[] = [
// {
// mobile: {
// main: animation('#oss-discord', { x: 0, y: 0, rotate: 1 }, animationOptions),
// reversed: animation('#oss-discord', { x: -1200, y: 0, rotate: 1 }, animationOptions)
// },
// desktop: {
// main: animation('#oss-discord', { x: 20, y: '-80vh', rotate: 15 }, animationOptions),
// reversed: animation('#oss-discord', { x: -100, y: '0vh', rotate: 15 }, animationOptions)
// }
// },
// {
// mobile: {
// main: animation('#oss-github', { x: 0, y: -10, rotate: -2 }, animationOptions),
// reversed: animation('#oss-github', { x: -1200, y: 10, rotate: -2 }, animationOptions)
// },
// desktop: {
// main: animation('#oss-github', { x: -100, y: '-55vh', rotate: 6.26 }, animationOptions),
// reversed: animation('#oss-github', { x: 0, y: '0vh', rotate: 6.26 }, animationOptions)
// }
// },
// {
// mobile: {
// main: animation('#oss-twitter', { x: 0, y: 10, rotate: -3 }, animationOptions),
// reversed: animation('#oss-twitter', { x: -1200, y: -10, rotate: -3 }, animationOptions)
// },
// desktop: {
// main: animation('#oss-twitter', { x: 100, y: '-70vh', rotate: -15 }, animationOptions),
// reversed: animation('#oss-twitter', { x: 0, y: '0vh', rotate: -15 }, animationOptions)
// }
// },
// {
// mobile: {
// main: animation('#oss-youtube', { x: 0, y: 5, rotate: 2 }, animationOptions),
// reversed: animation('#oss-youtube', { x: -1200, y: -5, rotate: 2 }, animationOptions)
// },
// desktop: {
// main: animation('#oss-youtube', { x: -100, y: '-55vh', rotate: -3.77 }, animationOptions),
// reversed: animation('#oss-youtube', { x: 0, y: '0vh', rotate: -3.77 }, animationOptions)
// }
// },
// {
// mobile: {
// main: animation('#oss-commits', { x: 0, y: -4, rotate: -1 }, animationOptions),
// reversed: animation('#oss-commits', { x: -1200, y: 4, rotate: -1 }, animationOptions)
// },
// desktop: {
// main: animation('#oss-commits', { x: 100, y: '-80vh', rotate: -10.2 }, animationOptions),
// reversed: animation('#oss-commits', { x: 0, y: '0vh', rotate: -10.2 }, animationOptions)
// }
// }
];
const animScale: Scale = [0, animations.length - 1];
const percentScale: Scale = [0.1, 0.8];
const scrollHandler = createScrollHandler(
animations.map(({ mobile, desktop }, i) => {
return {
percentage: toScale(i, animScale, percentScale),
whenAfter() {
const { main, reversed } = isMobile() ? mobile : desktop;
main.play();
return reversed.play;
}
};
})
);
const isMobile = () => {
return window.innerWidth < 1024;
};
let scrollInfo: ScrollInfo = {
percentage: 0,
traversed: 0,
remaning: Infinity
};
</script>
<div
id="products"
use:scroll
on:aw-scroll={({ detail }) => {
const { percentage } = detail;
scrollInfo = detail;
console.log(detail);
scrollHandler(percentage);
}}
on:aw-resize={({ detail }) => {
scrollHandler.reset();
const { percentage: scrollPercentage } = detail;
console.log('resize', scrollPercentage);
scrollHandler(scrollPercentage);
}}
>
<div class="sticky-wrapper">
<div class="text">
{#if scrollInfo.traversed > 0}
<span class="aw-badges aw-eyebrow" transition:slide={{ axis: 'x' }}>Products_</span>
{/if}
{#if scrollInfo.traversed > 600}
<h2 class="aw-display aw-u-color-text-primary" transition:slide={{ axis: 'x' }}>
Your backend, minus the hassle
</h2>
{/if}
{#if scrollInfo.traversed > 1500}
<p
class="aw-description aw-u-max-width-700 u-margin-inline-auto"
transition:fly={{
y: 16
}}
>
Build secure and scalable applications faster with Appwrite's core backend products and
spend more time building the best products.
</p>
{/if}
</div>
<Phone />
</div>
</div>
<style lang="scss">
#products {
height: 10000px;
position: relative;
}
.sticky-wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
position: sticky;
top: 0;
height: 100vh;
overflow: hidden;
padding-inline: 1.25rem;
--navbar-height: 8rem;
--padding-block: 7.5rem;
padding-block: calc(var(--navbar-height) + var(--padding-block)) var(--padding-block);
width: 100%;
height: 100vh;
text-align: center;
.text {
display: flex;
flex-direction: column;
align-items: center;
h2 {
white-space: nowrap;
margin-top: 1.5rem;
}
p {
margin-top: 1.25rem;
max-width: 48.875rem;
}
@media (min-width: 1024px) {
h2 {
max-width: 61.375rem;
}
}
}
}
</style>

View File

@@ -84,39 +84,40 @@ export function createScrollHandler(callbacks: ScrollCallback[]) {
return handler;
}
type ScrollDetail = {
scrollPercentage: number;
scrollY: number;
scrollHeight: number;
top: number;
export type ScrollInfo = {
percentage: number;
traversed: number;
remaning: number;
};
export const scroll: Action<
HTMLElement,
undefined,
{
'on:aw-scroll': (e: CustomEvent<ScrollDetail>) => void;
'on:aw-resize': (e: CustomEvent<ScrollDetail>) => void;
'on:aw-scroll': (e: CustomEvent<ScrollInfo>) => void;
'on:aw-resize': (e: CustomEvent<ScrollInfo>) => void;
}
> = (node) => {
const getScrollInfo = () => {
function getScrollInfo(): ScrollInfo {
const { top, height } = node.getBoundingClientRect();
const { innerHeight, scrollY } = window;
const { innerHeight } = window;
const scrollHeight = height - innerHeight;
const scrollPercentage = (-1 * top) / scrollHeight;
const traversed = scrollPercentage * scrollHeight;
const remaning = scrollHeight - traversed;
return {
scrollPercentage,
scrollY,
scrollHeight,
top
};
percentage: scrollPercentage,
traversed,
remaning
};
}
const handleScroll = () => {
node.dispatchEvent(
new CustomEvent<ScrollDetail>('aw-scroll', {
new CustomEvent<ScrollInfo>('aw-scroll', {
detail: getScrollInfo()
})
);
@@ -124,7 +125,7 @@ export const scroll: Action<
const handleResize = () => {
node.dispatchEvent(
new CustomEvent<ScrollDetail>('aw-resize', {
new CustomEvent<ScrollInfo>('aw-resize', {
detail: getScrollInfo()
})
);

View File

@@ -0,0 +1,51 @@
<div class="phone">
<div class="inner">
<slot />
</div>
</div>
<style lang="scss">
.phone {
@include border-gradient;
--m-border-size: 1px;
--m-border-radius: 2.5rem;
--m-border-gradient-after: linear-gradient(
180deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0) 125.11%
);
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(8px);
padding: 0.5rem;
width: 275px;
// height: 550px;
flex-shrink: 0;
aspect-ratio: 1 / 2;
}
.inner {
background-color: white;
border-radius: 2rem;
width: 100%;
height: 100%;
position: relative;
&::after {
content: '';
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 0.5rem;
border-radius: 100rem;
background: var(--label-color-light-primary, #000);
width: 6.25rem;
height: 0.25rem;
}
}
</style>

View File

@@ -2,3 +2,4 @@ export { default as FooterNav } from './FooterNav.svelte';
export { default as MainFooter } from './MainFooter.svelte';
export { default as PreFooter } from './PreFooter.svelte';
export { default as MobileNav } from './MobileNav.svelte';
export { default as Phone } from './Phone.svelte';

View File

@@ -6,6 +6,7 @@
import { Tabs } from '$lib/UI';
import PreFooter from '$lib/components/PreFooter.svelte';
import OpenSource from '$lib/animations/OpenSource.svelte';
import Products from '$lib/animations/Products.svelte';
</script>
<!-- <div
@@ -133,20 +134,7 @@
</div>
</div>
<div class="aw-big-padding-section-level-1">
<div class="aw-big-padding-section-level-2">
<div class="aw-container">
<div class="aw-hero aw-u-max-width-993">
<span class="aw-badges aw-eyebrow">Products_</span>
<h2 class="aw-display aw-u-color-text-primary">Your backend, minus the hassle</h2>
<p class="aw-description aw-u-max-width-700 u-margin-inline-auto">
Build secure and scalable applications faster with Appwrites core backend products
and spend more time building the best products.
</p>
</div>
</div>
</div>
</div>
<Products />
<div class="aw-big-padding-section-level-1 u-position-relative aw-white-section theme-light">
<div class="u-position-absolute u-inset-block-end-0 u-inset-inline-start u-width-full-line">

View File

@@ -52,59 +52,46 @@
color:hsl(var(--aw-color-greyscale-50));
}
&::before {
--m-border-gradient: linear-gradient(
--m-border-gradient-before: linear-gradient(
to bottom,
rgba(253, 54, 110, 0.48) 0%,
rgba(253, 54, 110, 0) 180%
);
}
&::after {
--m-border-gradient: radial-gradient(
--m-border-gradient-after: radial-gradient(
42.86% 42.86% at 50.55% -0%,
rgba(255, 255, 255, 0.2) 0%,
rgba(255, 255, 255, 0) 100%
);
}
&:where(:hover) {
background: rgba(253, 54, 110, 0.10);
box-shadow: 0px -6px 10px 0px rgba(253, 54, 110, 0.08) inset;
&::before {
--m-border-gradient: linear-gradient(
--m-border-gradient-before: linear-gradient(
180deg, rgba(253, 54, 110, 0.64) 0%,
rgba(253, 54, 110, 0.00) 163.1%
);
}
&::after {
--m-border-gradient: radial-gradient(
--m-border-gradient-after: radial-gradient(
42.86% 42.86% at 50.55% 0%,
rgba(255, 255, 255, 0.20) 0%,
rgba(255, 255, 255, 0.00) 100%
);
}
}
&:where(:active) {
background: rgba(253, 54, 110, 0.16);
box-shadow: 0px -6px 10px 0px rgba(253, 54, 110, 0.08) inset;
&::before {
--m-border-gradient:
--m-border-gradient-before:
linear-gradient(180deg, rgba(253, 54, 110, 0.64) 0%, rgba(253, 54, 110, 0.00) 163.1%);
}
&::after {
--m-border-gradient:
--m-border-gradient-after:
radial-gradient(42.86% 42.86% at 50.55% 0%, rgba(255, 255, 255, 0.32) 0%, rgba(255, 255, 255, 0.00) 100%);
}
}
&:where(:focus-visible) {
background: rgba(253, 54, 110, 0.04);
box-shadow: 0px 0px 0px 4px rgba(253, 54, 110, 0.16), 0px -6px 10px 0px rgba(253, 54, 110, 0.08) inset;
@@ -120,15 +107,15 @@
color:hsl(var(--aw-color-pink-500));
}
&::before {
--m-border-gradient:
linear-gradient(180deg, rgba(253, 54, 110, 0.19) 0%, rgba(253, 54, 110, 0.48) 100%);
}
&::after {
--m-border-gradient:
--m-border-gradient-before:
linear-gradient(180deg, rgba(253, 54, 110, 0.19) 0%, rgba(253, 54, 110, 0.48) 100%);
--m-border-gradient-after:
radial-gradient(42.86% 42.86% at 50.55% 0%, rgba(255, 255, 255, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%);
}
&:where(:hover) {
background: rgba(253, 54, 110, 0.10);

View File

@@ -56,18 +56,11 @@
--m-border-radius: var(--p-card-border-radius);
--m-border-size: #{pxToRem(1)};
border: none;
&::before {
--m-border-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.16) 0%, rgba(255, 255, 255, 0.00) 100%);
}
--m-border-gradient-before: linear-gradient(180deg, rgba(255, 255, 255, 0.16) 0%, rgba(255, 255, 255, 0.00) 100%);
&.is-transparent-pink {
&::before {
--m-border-gradient: linear-gradient(180deg, rgba(253, 54, 110, 0.48) 0%, rgba(253, 54, 110, 0.00) 100%);
}
&::after {
--m-border-gradient: radial-gradient(42.86% 42.86% at 50.55% 0%, rgba(255, 255, 255, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%);
}
--m-border-gradient-before: linear-gradient(180deg, rgba(253, 54, 110, 0.48) 0%, rgba(253, 54, 110, 0.00) 100%);
--m-border-gradient-after: radial-gradient(42.86% 42.86% at 50.55% 0%, rgba(255, 255, 255, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%);
}
}
}

View File

@@ -1,18 +1,26 @@
@mixin border-gradient {
position: relative;
&::before,
&::after {
@mixin border-gradient-inner {
content: '';
position: absolute;
inset: 0;
border-radius: var(--m-border-radius);
border: var(--m-border-size) solid transparent;
background: var(--m-border-gradient) border-box;
border: var(--m-border-size, 1px) solid transparent;
-webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: destination-out;
mask-composite: exclude;
pointer-events: none;
}
@mixin border-gradient {
position: relative;
border-radius: var(--m-border-radius);
&::before {
@include border-gradient-inner;
background: var(--m-border-gradient-before) border-box;
}
&::after {
@include border-gradient-inner;
background: var(--m-border-gradient-after) border-box;
}
}

View File

@@ -2,6 +2,13 @@ import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vitest/config';
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: `@use '$scss/abstract' as *;`
}
}
},
plugins: [sveltekit()],
test: {
include: ['src/**/*.{test,spec}.{js,ts}']