too many changes, forgot to commit smh

This commit is contained in:
2025-06-29 19:35:32 +02:00
parent 96a8604d4b
commit 60e3102257
17 changed files with 633 additions and 279 deletions

View File

@@ -0,0 +1,35 @@
<script lang="ts">
import { Checkbox as CheckboxPrimitive, type WithoutChildrenOrChild } from "bits-ui";
import Check from "@lucide/svelte/icons/check";
import Minus from "@lucide/svelte/icons/minus";
import { cn } from "$lib/utils.js";
let {
ref = $bindable(null),
checked = $bindable(false),
indeterminate = $bindable(false),
class: className,
...restProps
}: WithoutChildrenOrChild<CheckboxPrimitive.RootProps> = $props();
</script>
<CheckboxPrimitive.Root
bind:ref
class={cn(
"border-primary ring-offset-background focus-visible:ring-ring data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground peer box-content size-4 shrink-0 rounded-sm border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50",
className
)}
bind:checked
bind:indeterminate
{...restProps}
>
{#snippet children({ checked, indeterminate })}
<div class="flex size-4 items-center justify-center text-current">
{#if indeterminate}
<Minus class="size-3.5" />
{:else}
<Check class={cn("size-3.5", !checked && "text-transparent")} />
{/if}
</div>
{/snippet}
</CheckboxPrimitive.Root>

View File

@@ -0,0 +1,6 @@
import Root from "./checkbox.svelte";
export {
Root,
//
Root as Checkbox,
};

View File

@@ -0,0 +1,7 @@
import Root from "./label.svelte";
export {
Root,
//
Root as Label,
};

View File

@@ -0,0 +1,19 @@
<script lang="ts">
import { Label as LabelPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js";
let {
ref = $bindable(null),
class: className,
...restProps
}: LabelPrimitive.RootProps = $props();
</script>
<LabelPrimitive.Root
bind:ref
class={cn(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
className
)}
{...restProps}
/>

View File

@@ -0,0 +1,176 @@
<script lang="ts">
import cursor_default from '$assets/cursor.png';
import cursor_additive from '$assets/cursor-additive.png';
import { animate } from 'animejs';
import { onMount } from 'svelte';
let mouseX = $state(0);
let mouseY = $state(0);
let rotation = $state(0);
let isMouseDown = $state(false);
let isHoveringInteractive = $state(false);
let dragStartX = $state(0);
let dragStartY = $state(0);
let degrees = $state(0);
let applyRotation = $state(false);
function isInteractive(el: Element | null): boolean {
while (el) {
const tag = el.tagName.toLowerCase();
const role = el.getAttribute('role');
const computed = getComputedStyle(el);
if (
['button', 'a', 'input', 'select', 'textarea', 'label', 'option'].includes(tag) ||
(role && ['button', 'link', 'checkbox', 'combobox'].includes(role)) ||
computed.cursor === 'pointer'
) {
return true;
}
el = el.parentElement;
}
return false;
}
const handleMouseMove = (e: MouseEvent) => {
mouseX = e.clientX;
mouseY = e.clientY;
const deltaX = e.pageX - window.pageXOffset - dragStartX;
const deltaY = e.pageY - window.pageYOffset - dragStartY;
if (!applyRotation && isMouseDown && deltaX * deltaX + deltaY * deltaY > 30 * 100) {
applyRotation = true;
}
let newDegrees = (Math.atan2(-deltaX, deltaY) * 180) / Math.PI + 24.3;
let diff = (newDegrees - degrees) % 360;
if (diff < -180) diff += 360;
if (diff > 180) diff -= 360;
if (isMouseDown && applyRotation) {
degrees += diff;
} else {
degrees = 0;
}
const el = document.elementFromPoint(mouseX, mouseY);
isHoveringInteractive = isInteractive(el);
if (!isMouseDown) {
if (isHoveringInteractive) {
animate(cursorAdditive, {
opacity: 1,
duration: 800,
ease: (t: number) => (t - 1) ** 5 + 1,
});
} else {
animate(cursorAdditive, {
opacity: 0,
duration: 800,
ease: (t: number) => (t - 1) ** 5 + 1,
});
}
}
animate(cursor, {
duration: 180,
translateX: mouseX,
translateY: mouseY - 50,
ease: (t: number) => (t - 1) ** 3 + 1,
});
animate(cursor, {
duration: 1500,
rotate: degrees,
transformOrigin: '0px 0px 0',
ease: (t: number) => Math.pow(2, -10 * t) * Math.sin((t - 0.075) * 20.94) + 1 - 0.0005 * t,
});
};
const handleMouseDown = (event: MouseEvent) => {
dragStartX = event.clientX;
dragStartY = event.clientY;
isMouseDown = true;
animate(cursorInner, {
scale: 0.9,
duration: 800,
ease: (t: number) => (t - 1) ** 3 + 1,
});
animate(cursorAdditive, {
opacity: 1,
scale: 0.9,
duration: 800,
ease: (t: number) => (t - 1) ** 5 + 1,
});
};
const handleMouseUp = () => {
rotation = 0;
isMouseDown = false;
applyRotation = false;
animate(cursorInner, {
scale: 1,
duration: 500,
ease: (t: number) => Math.pow(2, -10 * t) * Math.sin((t - 0.075) * 20.94) + 1 - 0.0005 * t,
});
animate(cursorAdditive, {
opacity: 0,
duration: 500,
scale: 1,
ease: (t: number) => (t - 1) ** 5 + 1,
});
};
let cursor: HTMLElement;
let cursorInner: HTMLDivElement;
let cursorAdditive: HTMLImageElement;
/* onMount(() => {
const processMouseMove = (e: MouseEvent) =>
handleMouseMove(e.clientX, e.clientY, e.pageX, e.pageY);
document.addEventListener('pointermove', processMouseMove);
document.addEventListener('pointerdown', handleMouseDown);
document.addEventListener('pointerup', handleMouseUp);
return () => {
document.removeEventListener('pointermove', processMouseMove);
document.removeEventListener('pointerdown', handleMouseDown);
document.removeEventListener('pointerup', handleMouseUp);
};
}); */
</script>
<svelte:window
onmousemove={handleMouseMove}
onmousedown={handleMouseDown}
onmouseup={handleMouseUp}
/>
<div class="h-7 w-7 fixed pointer-events-none z-[99999]" bind:this={cursor}>
<div class="relative">
<img class="absolute top-0 left-0" src={cursor_default} bind:this={cursorInner} alt="cursor" />
<img
class="absolute top-0 left-0 opacity-0"
src={cursor_additive}
bind:this={cursorAdditive}
alt="cursor"
/>
</div>
</div>
<style>
:global(html),
:global(body),
:global(*),
:global(*:hover),
:global(button),
:global(a),
:global(input),
:global(select),
:global(textarea) {
cursor: none !important;
}
</style>

View File

@@ -19,7 +19,7 @@
});
</script>
<div data-tauri-drag-region class="titlebar z-[99999] border-b border-theme-800/90">
<div data-tauri-drag-region class="titlebar z-[60] border-b border-theme-800/90">
<div class="mr-auto ms-2 flex flex-row gap-2 items-center text-[1.05rem] font-semibold">
<img src={Logo} alt="EZPP Launcher Logo" class="h-11 w-11 inline-block" />
<span>EZPPLauncher</span>