chore: add custom cursor, add config system
This commit is contained in:
@@ -4,6 +4,9 @@
|
||||
import { animate } from 'animejs';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let { smoothCursor = true }: { smoothCursor?: boolean } =
|
||||
$props();
|
||||
|
||||
let mouseX = $state(0);
|
||||
let mouseY = $state(0);
|
||||
let rotation = $state(0);
|
||||
@@ -75,7 +78,7 @@
|
||||
}
|
||||
|
||||
animate(cursor, {
|
||||
duration: 180,
|
||||
duration: smoothCursor ? 180 : 0,
|
||||
translateX: mouseX,
|
||||
translateY: mouseY - 50,
|
||||
ease: (t: number) => (t - 1) ** 3 + 1,
|
||||
@@ -128,19 +131,12 @@
|
||||
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);
|
||||
|
||||
onMount(() => {
|
||||
document.documentElement.classList.add('hiddenCursor');
|
||||
return () => {
|
||||
document.removeEventListener('pointermove', processMouseMove);
|
||||
document.removeEventListener('pointerdown', handleMouseDown);
|
||||
document.removeEventListener('pointerup', handleMouseUp);
|
||||
document.documentElement.classList.remove('hiddenCursor');
|
||||
};
|
||||
}); */
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:window
|
||||
@@ -148,8 +144,10 @@
|
||||
onmousedown={handleMouseDown}
|
||||
onmouseup={handleMouseUp}
|
||||
/>
|
||||
|
||||
<div class="h-7 w-7 fixed pointer-events-none z-[99999]" bind:this={cursor}>
|
||||
<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
|
||||
@@ -162,15 +160,15 @@
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:global(html),
|
||||
:global(body),
|
||||
:global(*),
|
||||
:global(*:hover),
|
||||
:global(button),
|
||||
:global(a),
|
||||
:global(input),
|
||||
:global(select),
|
||||
:global(textarea) {
|
||||
:global(html.hiddenCursor),
|
||||
:global(html.hiddenCursor body),
|
||||
:global(html.hiddenCursor *),
|
||||
:global(html.hiddenCursor *:hover),
|
||||
:global(html.hiddenCursor button),
|
||||
:global(html.hiddenCursor a),
|
||||
:global(html.hiddenCursor input),
|
||||
:global(html.hiddenCursor select),
|
||||
:global(html.hiddenCursor textarea) {
|
||||
cursor: none !important;
|
||||
}
|
||||
</style>
|
||||
|
77
src/lib/config.ts
Normal file
77
src/lib/config.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import {
|
||||
BaseDirectory,
|
||||
exists,
|
||||
mkdir,
|
||||
readFile,
|
||||
readTextFile,
|
||||
writeFile,
|
||||
} from '@tauri-apps/plugin-fs';
|
||||
import * as path from '@tauri-apps/api/path';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { Crypto } from './crypto';
|
||||
import { enc } from 'crypto-js';
|
||||
|
||||
export class Config {
|
||||
private config: Record<string, unknown> = {};
|
||||
private crypto: Crypto | undefined;
|
||||
private configFilePath: string | undefined;
|
||||
|
||||
async init() {
|
||||
const hwid: string = (await invoke('get_hwid')) ?? 'recorderinsandybridge';
|
||||
|
||||
this.crypto = new Crypto(hwid);
|
||||
|
||||
const homeDir = await path.homeDir();
|
||||
const folderPath = await path.join(homeDir, '.ezpplauncher');
|
||||
this.configFilePath = await path.join(folderPath, 'user_settings');
|
||||
|
||||
const createFolder = !(await exists(folderPath));
|
||||
if (createFolder) await mkdir(folderPath);
|
||||
|
||||
const createConfig = !(await exists(this.configFilePath));
|
||||
if (createConfig) await this.save();
|
||||
else await this.load();
|
||||
}
|
||||
|
||||
private async load() {
|
||||
if (!this.configFilePath) throw Error('configFilePath not set');
|
||||
if (!this.crypto) throw Error('crypto not initialized');
|
||||
|
||||
const fileStream = await readTextFile(this.configFilePath);
|
||||
try {
|
||||
const decryptedJSON = JSON.parse(this.crypto.decrypt(fileStream)) as Record<string, unknown>;
|
||||
this.config = decryptedJSON;
|
||||
console.log('config file loaded');
|
||||
console.log(JSON.stringify(this.config));
|
||||
} catch (err) {
|
||||
console.log('failed to read file');
|
||||
this.config = {};
|
||||
await this.save();
|
||||
}
|
||||
}
|
||||
|
||||
async save() {
|
||||
if (!this.configFilePath) throw Error('configFilePath not set');
|
||||
if (!this.crypto) throw Error('crypto not initialized');
|
||||
const encryptedJSON = this.crypto.encrypt(JSON.stringify(this.config));
|
||||
|
||||
console.log(this.config);
|
||||
console.log('saving file...');
|
||||
console.log(encryptedJSON);
|
||||
await writeFile(this.configFilePath, Buffer.from(encryptedJSON), {
|
||||
append: false,
|
||||
});
|
||||
}
|
||||
|
||||
value(key: string) {
|
||||
console.log(this.config);
|
||||
return {
|
||||
set: <T>(val: T) => {
|
||||
this.config[key] = val;
|
||||
},
|
||||
get: <T>(fallback: T): T => {
|
||||
return (this.config[key] as T) ?? fallback;
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
37
src/lib/crypto.ts
Normal file
37
src/lib/crypto.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import cryptojs from 'crypto-js';
|
||||
|
||||
export class Crypto {
|
||||
private key: cryptojs.lib.WordArray;
|
||||
private ivLength: number;
|
||||
|
||||
constructor(key: string, opts?: { ivLength?: number }) {
|
||||
this.key = cryptojs.SHA256(key);
|
||||
this.ivLength = opts?.ivLength ?? 16;
|
||||
}
|
||||
|
||||
encrypt(str: string): string {
|
||||
const iv = cryptojs.lib.WordArray.random(this.ivLength);
|
||||
const encrypted = cryptojs.AES.encrypt(str, this.key, { iv });
|
||||
|
||||
const ivBase64 = iv.toString(cryptojs.enc.Base64);
|
||||
const ctBase64 = encrypted.ciphertext.toString(cryptojs.enc.Base64);
|
||||
|
||||
return `${ivBase64}:${ctBase64}`;
|
||||
}
|
||||
|
||||
decrypt(data: string): string {
|
||||
const [ivBase64, ctBase64] = data.split(':');
|
||||
|
||||
if (!ivBase64 || !ctBase64) throw new Error('Invalid input format');
|
||||
|
||||
const iv = cryptojs.enc.Base64.parse(ivBase64);
|
||||
const ciphertext = cryptojs.enc.Base64.parse(ctBase64);
|
||||
|
||||
const cipherParams = cryptojs.lib.CipherParams.create({
|
||||
ciphertext,
|
||||
});
|
||||
|
||||
const decrypted = cryptojs.AES.decrypt(cipherParams, this.key, { iv });
|
||||
return decrypted.toString(cryptojs.enc.Utf8);
|
||||
}
|
||||
}
|
7
src/lib/userSettings.ts
Normal file
7
src/lib/userSettings.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import { Config } from './config';
|
||||
|
||||
export const userSettings = writable<Config>(new Config());
|
||||
|
||||
export const customCursor = writable<boolean>(true);
|
||||
export const cursorSmoothening = writable<boolean>(true);
|
Reference in New Issue
Block a user