Files
spacedrive/interface/components/Sparkles.tsx
Vítor Vasconcellos ea92383b78 Improve file thumbnails and Quick Preview (+ some code clean-up and rust deps update) (#2758)
* Update rspc, prisma-client-rust, axum and tanstack-query
 - Deleted some unused examples and fully commented out frontend code
 - Implement many changes required due to the updates
 - Update most rust dependencies

* Re-enable p2p

* Fix server

* Auto format

* Fix injected script format
 - Update some github actions
 - Update pnpm lock file

* Fix devtools showing up when app opens
 - Fix million complaining about Sparkles component

* Fix sd-server

* Fix and improve thumbnails rendering
 - Fix core always saying a new thumbnail was generated even for files that it skiped thumbnail generation
 - Rewrite FileThumb and improve related components

* Ignore tmp files when running prettier

* Improve FileThumb component performance
 - Rework useExplorerDraggable and useExplorerItemData hooks due to reduce unecessary re-renders

* More fixes for thumb component
 - A couple of minor performance improvements to frontend code

* auto format

* Fix Thumbnail and QuickPreview

* Fix logic for when to show 'fail to load original' error message in QuickPreview
 - Updated prisma-client-rust, libp2p, tauri, tauri-specta, rspc and hyper

* Fix type checking
 - Format scripts

* Add script prettier config

* Fix serde missing feature
 - Use rust-libp2p spacedrive fork again
 - Update rspc

* Autoformat + fix pnpm lock

* Fix thumbnail first load again

* Autoformat

* autoformat

* Fix rust-libp2p fork url again?

* Remove usePathsInfiniteQuery hook

* Update tauri 2.0.6
2024-10-21 15:47:40 +00:00

101 lines
2.4 KiB
TypeScript

'use client';
import { useState } from 'react';
import { usePrefersReducedMotion, useRandomInterval } from '~/hooks';
const DEFAULT_COLOR = '#FFC700';
const random = (min: number, max: number) => Math.floor(Math.random() * (max - min)) + min;
const range = (start: number, end?: number, step = 1) => {
const output = [];
if (typeof end === 'undefined') {
end = start;
start = 0;
}
for (let i = start; i < end; i += step) {
output.push(i);
}
return output;
};
const generateSparkle = (color: string) => {
const sparkle = {
id: String(random(10000, 99999)),
createdAt: Date.now(),
color,
size: random(10, 20),
style: {
top: random(0, 100) + '%',
left: random(0, 100) + '%'
}
};
return sparkle;
};
type SparklesProps = {
color?: string;
children: React.ReactNode;
};
// million-ignore
const Sparkles = ({ color = DEFAULT_COLOR, children }: SparklesProps) => {
const [sparkles, setSparkles] = useState(() => {
return range(3).map(() => generateSparkle(color));
});
const prefersReducedMotion = usePrefersReducedMotion();
useRandomInterval(
() => {
const sparkle = generateSparkle(color);
const now = Date.now();
const nextSparkles = sparkles.filter((sp) => {
const delta = now - sp.createdAt;
return delta < 750;
});
nextSparkles.push(sparkle);
setSparkles(nextSparkles);
},
prefersReducedMotion ? null : 100,
prefersReducedMotion ? null : 1000
);
return (
<span className="relative inline-block">
{sparkles.map((sparkle) => (
<span
key={sparkle.id}
className="z-10"
style={{
position: 'absolute',
display: 'block',
animation: prefersReducedMotion ? 'none' : 'comeInOut 700ms forwards',
...sparkle.style
}}
>
<svg
width={sparkle.size}
height={sparkle.size}
viewBox="0 0 68 68"
fill="none"
style={{
display: 'block',
animation: prefersReducedMotion ? 'none' : 'spin 1000ms linear'
}}
>
<path
d="M26.5 25.5C19.0043 33.3697 0 34 0 34C0 34 19.1013 35.3684 26.5 43.5C33.234 50.901 34 68 34 68C34 68 36.9884 50.7065 44.5 43.5C51.6431 36.647 68 34 68 34C68 34 51.6947 32.0939 44.5 25.5C36.5605 18.2235 34 0 34 0C34 0 33.6591 17.9837 26.5 25.5Z"
fill={sparkle.color}
/>
</svg>
</span>
))}
<strong style={{ position: 'relative', zIndex: 1, fontWeight: 'bold' }}>
{children}
</strong>
</span>
);
};
export default Sparkles;