feat: Add qwik-react (#103)

This adds the following pages:

The landing page (/)
The pricing page (/pricing)
The contact page (/contact)
The changelog page (/changelog)
Terms Of Service page (/terms)
Privacy Policy (/privacy)
This commit is contained in:
Wanjohi
2024-08-30 16:19:58 +03:00
committed by GitHub
parent d13d3dc5d8
commit 73cec51728
102 changed files with 5096 additions and 105 deletions

View File

@@ -0,0 +1,105 @@
/* eslint-disable qwik/no-use-visible-task */
import { cn } from '@/design';
import { component$, useSignal, useTask$, useStyles$, useVisibleTask$, $ } from '@builder.io/qwik';
interface ImageLoaderProps {
src: string;
alt: string;
width?: number;
height?: number;
class?: string;
}
export const BasicImageLoader = component$((props: ImageLoaderProps) => {
const imageLoaded = useSignal(false);
const hasError = useSignal(false);
const imgRef = useSignal<HTMLImageElement>();
useStyles$(`
@keyframes gradientShift {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
.loading-animation {
animation: gradientShift 1.5s infinite linear;
background-size: 200% 100%;
}
`);
useTask$(({ track }) => {
track(() => props.src);
imageLoaded.value = false;
hasError.value = false;
});
useVisibleTask$(async ({ cleanup }) => {
const img = imgRef.value;
if (!img) return;
// const imageData = await imageGetter();
const checkImageLoaded = async () => {
if (img.complete && img.naturalHeight !== 0) {
imageLoaded.value = true;
}
};
// Check immediately in case the image is already loaded
await checkImageLoaded();
// Set up event listeners
const loadHandler = async () => {
imageLoaded.value = true;
};
const errorHandler = () => {
hasError.value = true;
};
img.addEventListener('load', loadHandler);
img.addEventListener('error', errorHandler);
// Use MutationObserver to detect src changes
const observer = new MutationObserver(checkImageLoaded);
observer.observe(img, { attributes: true, attributeFilter: ['src'] });
cleanup(() => {
img.removeEventListener('load', loadHandler);
img.removeEventListener('error', errorHandler);
observer.disconnect();
});
});
return (
<>
{!imageLoaded.value && !hasError.value && (
<div
class={cn("relative x-[20] inset-0 h-full loading-animation bg-gradient-to-r from-gray-200 via-gray-300 to-gray-200 dark:from-gray-800 dark:via-gray-900 dark:to-gray-800", props.class)}
style={{
height: props.height,
aspectRatio: props.width && props.height ? `${props.width} / ${props.height}` : 'auto'
}}
/>
)}
<img
src={props.src}
draggable={false}
alt={props.alt}
width={props.width}
height={props.height}
ref={imgRef}
class={{
'z-[5] relative': imageLoaded.value,
'hidden': !imageLoaded.value && !hasError.value,
'w-full h-full': imageLoaded.value,
'w-16 h-16 text-red-500': hasError.value,
[props.class || '']: !!props.class,
}}
/>
{hasError.value && (
<p class="text-red-500 text-sm" >
Error loading image
</p>
)}
</>
);
});