refactor: auto format

This commit is contained in:
waltem01 2024-03-14 15:25:46 +01:00
parent 04f905a841
commit 100d37e552
11 changed files with 638 additions and 640 deletions

View File

@ -18,10 +18,10 @@ export function hexToRgb(hex: string): Color | null {
const result = /^([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); const result = /^([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result return result
? { ? {
r: parseInt(result[1], 16), r: parseInt(result[1], 16),
g: parseInt(result[2], 16), g: parseInt(result[2], 16),
b: parseInt(result[3], 16) b: parseInt(result[3], 16)
} }
: null; : null;
} }
@ -36,7 +36,5 @@ export function getLuminance(rgb: Color): number {
// Convert an rgb color object to a hex color string // Convert an rgb color object to a hex color string
export function rgbToHex(color: Color): string { export function rgbToHex(color: Color): string {
return [color.r, color.g, color.b] return [color.r, color.g, color.b].map((e) => e.toString(16).padStart(2, '0')).join('');
.map((e) => e.toString(16).padStart(2, '0'))
.join('');
} }

View File

@ -1,23 +1,22 @@
import type { APIResponse } from '$lib/interfaces'; import type { APIResponse } from '$lib/interfaces';
export async function redirectAPI({ form, fdata }: { form?: HTMLFormElement; fdata?: FormData }) { export async function redirectAPI({ form, fdata }: { form?: HTMLFormElement; fdata?: FormData }) {
if (!fdata && form) fdata = new FormData(form); if (!fdata && form) fdata = new FormData(form);
else if (!fdata) throw new Error('No formdata provided!'); else if (!fdata) throw new Error('No formdata provided!');
// Get endpoint, prefer form, then formdata or empty // Get endpoint, prefer form, then formdata or empty
const endpoint = (form?.dataset.endpoint ?? fdata.get('endpoint')) ?? ''; const endpoint = form?.dataset.endpoint ?? fdata.get('endpoint') ?? '';
// Append endpoint to formdata // Append endpoint to formdata
if (!fdata?.has('endpoint')) if (!fdata?.has('endpoint')) fdata.append('endpoint', endpoint);
fdata.append('endpoint', endpoint);
// Send request to be redirected to given endpoint
// Send request to be redirected to given endpoint const response = await fetch('/api/redirect', {
const response = await fetch('/api/redirect', { method: 'POST',
method: 'POST', body: fdata
body: fdata });
});
// Await respose from webserver
// Await respose from webserver const mdata = (await response.json()) as APIResponse;
const mdata = (await response.json()) as APIResponse; // Basic error handling
// Basic error handling if (!mdata.success) alert(`Error while processing '${endpoint}'!`);
if (!mdata.success) alert(`Error while processing '${endpoint}'!`); }
}

View File

@ -46,9 +46,6 @@ export function createGridArray(matrix: Matrix): MatrixCell[][] {
const { factor } = scale; const { factor } = scale;
return Array.from({ length: height / factor }, (_, y) => return Array.from({ length: height / factor }, (_, y) =>
Array.from( Array.from({ length: width / factor }, (_, x) => ({ x, y, color: '000000' }) as MatrixCell)
{ length: width / factor },
(_, x) => ({ x, y, color: '000000' }) as MatrixCell
)
) as MatrixCell[][]; ) as MatrixCell[][];
} }

View File

@ -2,4 +2,4 @@ import { API_SERVER_IP, API_SERVER_PORT } from '$env/static/private';
export function buildAPIStr(endpoint: string) { export function buildAPIStr(endpoint: string) {
return `http://${API_SERVER_IP ?? 'localhost'}:${API_SERVER_PORT ?? '8080'}/${endpoint}`; return `http://${API_SERVER_IP ?? 'localhost'}:${API_SERVER_PORT ?? '8080'}/${endpoint}`;
} }

View File

@ -1,10 +1,10 @@
<h1 class="font-bold text-2xl">Did you mean:</h1> <h1 class="font-bold text-2xl">Did you mean:</h1>
<h2 class="font-bold text-xl"> <h2 class="font-bold text-xl">
<a class="underline text-blue-600" href="/admin">Admin/Control Panel</a> <a class="underline text-blue-600" href="/admin">Admin/Control Panel</a>
</h2> </h2>
<h2 class="font-bold text-xl"> <h2 class="font-bold text-xl">
<a class="underline text-blue-600" href="/image">Image upload</a> <a class="underline text-blue-600" href="/image">Image upload</a>
</h2> </h2>
<h2 class="font-bold text-xl"> <h2 class="font-bold text-xl">
<a class="underline text-blue-600" href="/clock">Clock</a> <a class="underline text-blue-600" href="/clock">Clock</a>
</h2> </h2>

View File

@ -227,7 +227,9 @@
matrix = initializeMatrix(); matrix = initializeMatrix();
matrix.scale = { matrix.scale = {
factor: 4, factor: 4,
// 0.1875 (made up padding) * 192 (height when it was made up) * 4 (scaling when it was made up) // 0.1875 (made up padding) *
// 192 (height when it was made up) *
// 4 (scaling when it was made up)
padding: 144 / matrix.width padding: 144 / matrix.width
}; };
matrix.grid = createGridArray(matrix); matrix.grid = createGridArray(matrix);

View File

@ -1,28 +1,28 @@
import type { APIResponse } from "$lib/interfaces"; import type { APIResponse } from '$lib/interfaces';
import { json, type RequestHandler } from "@sveltejs/kit"; import { json, type RequestHandler } from '@sveltejs/kit';
export const GET: RequestHandler = async ({ url }) => { export const GET: RequestHandler = async ({ url }) => {
// Get endpoint on main API from searchparams // Get endpoint on main API from searchparams
const params = url.searchParams; const params = url.searchParams;
const subreddit = params.get('subreddit'); const subreddit = params.get('subreddit');
// Return if param not found // Return if param not found
if (subreddit === null) return json({ success: false } as APIResponse); if (subreddit === null) return json({ success: false } as APIResponse);
// Get subreddit page data // Get subreddit page data
const response = await fetch(`https://www.reddit.com/r/${subreddit}/`, { const response = await fetch(`https://www.reddit.com/r/${subreddit}/`, {
headers: new Headers({ headers: new Headers({
"User-Agent": "MatrixRedditMemes/0.0.1" 'User-Agent': 'MatrixRedditMemes/0.0.1'
}) })
}); });
// Read data as string // Read data as string
const text = await response.text(); const text = await response.text();
// Get all sources of posts // Get all sources of posts
const regex = /<img[^>]+role="presentation"[^>]+src="(.*?)"[^>]*>/g; const regex = /<img[^>]+role="presentation"[^>]+src="(.*?)"[^>]*>/g;
let results = [], match; let results = [],
while ((match = regex.exec(text)) !== null) match;
results.push(match[1]); while ((match = regex.exec(text)) !== null) results.push(match[1]);
// Return source data // Return source data
return json({ success: true, results } as APIResponse); return json({ success: true, results } as APIResponse);
}; };

View File

@ -1,241 +1,241 @@
<script lang="ts"> <script lang="ts">
import { initializeMatrix, type Matrix } from '$lib/client/matrix'; import { initializeMatrix, type Matrix } from '$lib/client/matrix';
import { redirectAPI } from '$lib/client/httpRequests'; import { redirectAPI } from '$lib/client/httpRequests';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
// Data structure to keep track of clock // Data structure to keep track of clock
interface Clock { interface Clock {
// Clock circle radius // Clock circle radius
body: number; body: number;
// Clock hand radii // Clock hand radii
hands: { hands: {
second: number; second: number;
minute: number; minute: number;
hour: number; hour: number;
}; };
// Clock time percentages // Clock time percentages
time: { time: {
second: number; second: number;
minute: number; minute: number;
hour: number; hour: number;
}; };
// Clock hand positions // Clock hand positions
positions?: { positions?: {
second: { second: {
x: number; x: number;
y: number; y: number;
}; };
minute: { minute: {
x: number; x: number;
y: number; y: number;
}; };
hour: { hour: {
x: number; x: number;
y: number; y: number;
}; };
}; };
// Clock update speed in seconds // Clock update speed in seconds
speed: number; speed: number;
} }
// Data structure to keep track of params when displaying clock parts on matrix // Data structure to keep track of params when displaying clock parts on matrix
interface DisplayParams { interface DisplayParams {
x: string; x: string;
y: string; y: string;
r?: string; r?: string;
position?: { position?: {
x: string; x: string;
y: string; y: string;
}; };
} }
//.System variables //.System variables
let clockEnabled: boolean = false; let clockEnabled: boolean = false;
let matrix: Matrix; let matrix: Matrix;
const clock: Clock = { const clock: Clock = {
body: 48, body: 48,
hands: { hands: {
second: 40, second: 40,
minute: 30, minute: 30,
hour: 15 hour: 15
}, },
time: { time: {
second: 0, second: 0,
minute: 0, minute: 0,
hour: 0 hour: 0
}, },
speed: 1.25 speed: 1.25
}; };
// Constant system values // Constant system values
const TWO_PI = 2 * Math.PI; const TWO_PI = 2 * Math.PI;
const HALF_PI = Math.PI / 2; const HALF_PI = Math.PI / 2;
// Calculate (x = r * cos(a), y = r * sin(a)) // Calculate (x = r * cos(a), y = r * sin(a))
function calcPos(time: 'second' | 'minute' | 'hour', operation: 'sin' | 'cos') { function calcPos(time: 'second' | 'minute' | 'hour', operation: 'sin' | 'cos') {
const radius = clock.hands[time]; const radius = clock.hands[time];
const angle = TWO_PI * clock.time[time]; const angle = TWO_PI * clock.time[time];
const relative = Math[operation](angle - HALF_PI); const relative = Math[operation](angle - HALF_PI);
return 50 + radius * relative; return 50 + radius * relative;
} }
async function update() { async function update() {
// Get current datetime and date // Get current datetime and date
const current = new Date(Date.now()); const current = new Date(Date.now());
const day = new Date(current.toDateString()); const day = new Date(current.toDateString());
// Calculate millis diff between now and midnight // Calculate millis diff between now and midnight
const milli = current.getTime() - day.getTime(); const milli = current.getTime() - day.getTime();
// Calculate seconds, minutes and hours // Calculate seconds, minutes and hours
const second = milli / 1000; const second = milli / 1000;
const minute = second / 60; const minute = second / 60;
const hour = minute / 60; const hour = minute / 60;
// Update time variables // Update time variables
clock.time = { clock.time = {
second: second / 60, second: second / 60,
minute: minute / 60, minute: minute / 60,
hour: (hour % 12) / 12 hour: (hour % 12) / 12
}; };
// Update hand positions // Update hand positions
clock.positions = { clock.positions = {
second: { second: {
x: calcPos('second', 'cos'), x: calcPos('second', 'cos'),
y: calcPos('second', 'sin') y: calcPos('second', 'sin')
}, },
minute: { minute: {
x: calcPos('minute', 'cos'), x: calcPos('minute', 'cos'),
y: calcPos('minute', 'sin') y: calcPos('minute', 'sin')
}, },
hour: { hour: {
x: calcPos('hour', 'cos'), x: calcPos('hour', 'cos'),
y: calcPos('hour', 'sin') y: calcPos('hour', 'sin')
} }
}; };
// If enabled, update clock display // If enabled, update clock display
if (clockEnabled) await displayMatrixClock(); if (clockEnabled) await displayMatrixClock();
} }
// Displays a clock part on the matrix display // Displays a clock part on the matrix display
async function displayClockPart( async function displayClockPart(
part: 'body' | 'seconds' | 'minutes' | 'hours', part: 'body' | 'seconds' | 'minutes' | 'hours',
params: DisplayParams params: DisplayParams
) { ) {
const fdata = new FormData(); const fdata = new FormData();
if (part === 'body') { if (part === 'body') {
// If part is 'body', append the 'r' parameter to the form data // If part is 'body', append the 'r' parameter to the form data
fdata.append('endpoint', 'circle'); fdata.append('endpoint', 'circle');
fdata.append('x', params.x); fdata.append('x', params.x);
fdata.append('y', params.y); fdata.append('y', params.y);
fdata.append('r', params.r!); fdata.append('r', params.r!);
} else { } else {
// If part is not 'body', convert the position coordinates to matrix coordinates and append to form data // If part is not 'body', convert the position coordinates to matrix coordinates and append to form data
const coords = coordsToMatrix(params.position!.x, params.position!.y); const coords = coordsToMatrix(params.position!.x, params.position!.y);
fdata.append('endpoint', 'line'); fdata.append('endpoint', 'line');
fdata.append('x1', params.x); fdata.append('x1', params.x);
fdata.append('y1', params.y); fdata.append('y1', params.y);
fdata.append('x2', coords.x); fdata.append('x2', coords.x);
fdata.append('y2', coords.y); fdata.append('y2', coords.y);
} }
return await redirectAPI({ fdata }); return await redirectAPI({ fdata });
} }
// Converts the x and y number values in the given positions object to strings // Converts the x and y number values in the given positions object to strings
function convertNumbers(positions: { x: number; y: number }): { x: string; y: string } { function convertNumbers(positions: { x: number; y: number }): { x: string; y: string } {
return { return {
x: positions.x.toString(), x: positions.x.toString(),
y: positions.y.toString() y: positions.y.toString()
}; };
} }
// Converts the x and y values from percentage to matrix coordinates // Converts the x and y values from percentage to matrix coordinates
function coordsToMatrix(x: string, y: string): { x: string; y: string } { function coordsToMatrix(x: string, y: string): { x: string; y: string } {
// Calculate the matrix coordinates based on the percentage values of x and y // Calculate the matrix coordinates based on the percentage values of x and y
return convertNumbers({ return convertNumbers({
x: Math.round((Number(x) / 100) * matrix.width), x: Math.round((Number(x) / 100) * matrix.width),
y: Math.round((Number(y) / 100) * matrix.height) y: Math.round((Number(y) / 100) * matrix.height)
}); });
} }
// Displays the clock on the matrix display, converting number values to strings where necessary // Displays the clock on the matrix display, converting number values to strings where necessary
async function displayMatrixClock() { async function displayMatrixClock() {
const middle = coordsToMatrix('50', '50'); const middle = coordsToMatrix('50', '50');
// Display the body of the clock // Display the body of the clock
await displayClockPart('body', { await displayClockPart('body', {
x: middle.x, x: middle.x,
y: middle.y, y: middle.y,
r: ((clock.body / 100) * matrix.height).toFixed(0) r: ((clock.body / 100) * matrix.height).toFixed(0)
}); });
// Display the seconds of the clock, converting position coordinates to strings // Display the seconds of the clock, converting position coordinates to strings
await displayClockPart('seconds', { await displayClockPart('seconds', {
x: middle.x, x: middle.x,
y: middle.y, y: middle.y,
position: convertNumbers(clock.positions?.second!) position: convertNumbers(clock.positions?.second!)
}); });
// Display the minutes of the clock, converting position coordinates to strings // Display the minutes of the clock, converting position coordinates to strings
await displayClockPart('minutes', { await displayClockPart('minutes', {
x: middle.x, x: middle.x,
y: middle.y, y: middle.y,
position: convertNumbers(clock.positions?.minute!) position: convertNumbers(clock.positions?.minute!)
}); });
// Display the hours of the clock, converting position coordinates to strings // Display the hours of the clock, converting position coordinates to strings
await displayClockPart('hours', { await displayClockPart('hours', {
x: middle.x, x: middle.x,
y: middle.y, y: middle.y,
position: convertNumbers(clock.positions?.hour!) position: convertNumbers(clock.positions?.hour!)
}); });
// Update the clock by fetching the update API endpoint // Update the clock by fetching the update API endpoint
await fetch('/api/redirect?endpoint=update'); await fetch('/api/redirect?endpoint=update');
} }
onMount(() => { onMount(() => {
setInterval(update, clock.speed * 1000); setInterval(update, clock.speed * 1000);
matrix = initializeMatrix(); matrix = initializeMatrix();
}); });
</script> </script>
<!-- Title --> <!-- Title -->
<h1 class="text-4xl font-bold m-5 text-center">Matrix Clock Display</h1> <h1 class="text-4xl font-bold m-5 text-center">Matrix Clock Display</h1>
<!-- Update toggle form --> <!-- Update toggle form -->
<form class="m-1 grid grid-cols-2" on:submit|preventDefault={() => (clockEnabled = !clockEnabled)}> <form class="m-1 grid grid-cols-2" on:submit|preventDefault={() => (clockEnabled = !clockEnabled)}>
<label class="border-2 border-black border-r-0 pl-1" for="toggle">Toggle clock usage:</label> <label class="border-2 border-black border-r-0 pl-1" for="toggle">Toggle clock usage:</label>
<input <input
class="border-2 border-black cursor-pointer hover:bg-gray-200" class="border-2 border-black cursor-pointer hover:bg-gray-200"
id="toggle" id="toggle"
type="submit" type="submit"
value="Submit" value="Submit"
/> />
</form> </form>
<!-- Virtual clock display using SVG --> <!-- Virtual clock display using SVG -->
<div class="bg-black"> <div class="bg-black">
<svg class="text-white" viewBox="0 0 100 100"> <svg class="text-white" viewBox="0 0 100 100">
<!-- Clock body --> <!-- Clock body -->
<circle class="stroke-current" cx="50" cy="50" r={clock.body} fill="none" stroke-width="2" /> <circle class="stroke-current" cx="50" cy="50" r={clock.body} fill="none" stroke-width="2" />
<!-- Clock seconds hand --> <!-- Clock seconds hand -->
<line <line
class="stroke-current" class="stroke-current"
x1="50" x1="50"
y1="50" y1="50"
x2={clock.positions?.second.x ?? 50} x2={clock.positions?.second.x ?? 50}
y2={clock.positions?.second.y ?? 50} y2={clock.positions?.second.y ?? 50}
stroke-width=".5" stroke-width=".5"
/> />
<!-- Clock minutes hand --> <!-- Clock minutes hand -->
<line <line
class="stroke-current" class="stroke-current"
x1="50" x1="50"
y1="50" y1="50"
x2={clock.positions?.minute.x ?? 50} x2={clock.positions?.minute.x ?? 50}
y2={clock.positions?.minute.y ?? 50} y2={clock.positions?.minute.y ?? 50}
stroke-width="1" stroke-width="1"
/> />
<!-- Clock hours hand --> <!-- Clock hours hand -->
<line <line
class="stroke-current" class="stroke-current"
x1="50" x1="50"
y1="50" y1="50"
x2={clock.positions?.hour.x ?? 50} x2={clock.positions?.hour.x ?? 50}
y2={clock.positions?.hour.y ?? 50} y2={clock.positions?.hour.y ?? 50}
stroke-width="2" stroke-width="2"
/> />
</svg> </svg>
</div> </div>

View File

@ -1,319 +1,319 @@
<script lang="ts"> <script lang="ts">
import { initializeMatrix, type Matrix } from '$lib/client/matrix'; import { initializeMatrix, type Matrix } from '$lib/client/matrix';
import { redirectAPI } from '$lib/client/httpRequests'; import { redirectAPI } from '$lib/client/httpRequests';
import type { APIResponse } from '$lib/interfaces'; import type { APIResponse } from '$lib/interfaces';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
// Data structure to keep track of upload statistics // Data structure to keep track of upload statistics
interface UploadStat { interface UploadStat {
start: number; start: number;
elapsed: string; elapsed: string;
interval: NodeJS.Timeout; interval: NodeJS.Timeout;
} }
// Data structure to represent user data // Data structure to represent user data
interface SubmitData { interface SubmitData {
x: number; x: number;
y: number; y: number;
width: number; width: number;
height: number; height: number;
update: boolean; update: boolean;
subreddit?: string; subreddit?: string;
} }
// Data structure to represent subreddit posts // Data structure to represent subreddit posts
interface RedditPosts { interface RedditPosts {
sources: string[]; sources: string[];
index: number; index: number;
interval: NodeJS.Timeout; interval: NodeJS.Timeout;
} }
// System variables // System variables
let imageURL: string | null; let imageURL: string | null;
let uploadData: UploadStat, matrix: Matrix; let uploadData: UploadStat, matrix: Matrix;
let uploadStarted = false, let uploadStarted = false,
submitData: SubmitData, submitData: SubmitData,
posts: RedditPosts; posts: RedditPosts;
// Update matrix over endpoint // Update matrix over endpoint
async function updateMatrix(data: SubmitData) { async function updateMatrix(data: SubmitData) {
if (data.update) await fetch('/api/redirect?endpoint=update'); if (data.update) await fetch('/api/redirect?endpoint=update');
clearInterval(uploadData.interval); clearInterval(uploadData.interval);
} }
// Placing image over endpoint (by specifying position) // Placing image over endpoint (by specifying position)
// Image is always max resolution! See resizing in `fileAsDataURL`. // Image is always max resolution! See resizing in `fileAsDataURL`.
async function placeImage(data: SubmitData) { async function placeImage(data: SubmitData) {
const fdata = new FormData(); const fdata = new FormData();
fdata.append('x', data.x.toString()); fdata.append('x', data.x.toString());
fdata.append('y', data.y.toString()); fdata.append('y', data.y.toString());
await post(fdata, 'image'); await post(fdata, 'image');
} }
// Send image data to endpoint // Send image data to endpoint
async function sendImage(url: string) { async function sendImage(url: string) {
const fdata = new FormData(); const fdata = new FormData();
fdata.append('url', url); fdata.append('url', url);
await post(fdata, 'upload'); await post(fdata, 'upload');
} }
// Handle sending HTTP POST request with specified data // Handle sending HTTP POST request with specified data
async function post(fdata: FormData, endpoint: string) { async function post(fdata: FormData, endpoint: string) {
// Append endpoint to formdata for redirection // Append endpoint to formdata for redirection
fdata.append('endpoint', endpoint); fdata.append('endpoint', endpoint);
redirectAPI({ fdata }); redirectAPI({ fdata });
} }
// Load and read file, encode as base64 data url // Load and read file, encode as base64 data url
async function fileAsDataURL(data: SubmitData): Promise<string> { async function fileAsDataURL(data: SubmitData): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const img = new Image(); const img = new Image();
img.onload = () => { img.onload = () => {
const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
const context = canvas.getContext('2d'); const context = canvas.getContext('2d');
// Set the canvas dimensions // Set the canvas dimensions
canvas.width = data.width; canvas.width = data.width;
canvas.height = data.height; canvas.height = data.height;
// Draw the image onto the canvas, resizing it to fit the canvas // Draw the image onto the canvas, resizing it to fit the canvas
context?.drawImage(img, 0, 0, canvas.width, canvas.height); context?.drawImage(img, 0, 0, canvas.width, canvas.height);
// Convert the canvas image to a Data URL // Convert the canvas image to a Data URL
resolve(canvas.toDataURL()); resolve(canvas.toDataURL());
}; };
img.onerror = reject; img.onerror = reject;
// Load image by assigning url // Load image by assigning url
img.src = imageURL!; img.src = imageURL!;
}); });
} }
// Getting an image from input // Getting an image from input
function getImage(event: Event) { function getImage(event: Event) {
uploadStarted = false; uploadStarted = false;
// Revoke previous image url, if any // Revoke previous image url, if any
if (imageURL) { if (imageURL) {
URL.revokeObjectURL(imageURL); URL.revokeObjectURL(imageURL);
imageURL = null; imageURL = null;
} }
// Get user input // Get user input
const input = event.target as HTMLInputElement; const input = event.target as HTMLInputElement;
const file = input?.files?.[0]; const file = input?.files?.[0];
if (!file) return; if (!file) return;
// Load image data from file // Load image data from file
imageURL = URL.createObjectURL(file); imageURL = URL.createObjectURL(file);
} }
// Handling form submit event // Handling form submit event
function handleSubmit(event: SubmitEvent) { function handleSubmit(event: SubmitEvent) {
// Get image data from submit // Get image data from submit
const form = event.target as HTMLFormElement; const form = event.target as HTMLFormElement;
const fdata = new FormData(form); const fdata = new FormData(form);
submitData = { submitData = {
x: parseInt(fdata.get('x')?.toString() ?? '0'), x: parseInt(fdata.get('x')?.toString() ?? '0'),
y: parseInt(fdata.get('y')?.toString() ?? '0'), y: parseInt(fdata.get('y')?.toString() ?? '0'),
width: parseInt(fdata.get('w')?.toString() ?? matrix.width.toString()), width: parseInt(fdata.get('w')?.toString() ?? matrix.width.toString()),
height: parseInt(fdata.get('h')?.toString() ?? matrix.height.toString()), height: parseInt(fdata.get('h')?.toString() ?? matrix.height.toString()),
update: fdata.get('update') ? true : false, update: fdata.get('update') ? true : false,
subreddit: fdata.get('subreddit')?.toString() subreddit: fdata.get('subreddit')?.toString()
}; };
// Time upload by saving date // Time upload by saving date
uploadData = { uploadData = {
interval: setInterval(() => { interval: setInterval(() => {
const now = performance.now(); const now = performance.now();
const diff = now - uploadData.start; const diff = now - uploadData.start;
const secs = diff / 1000; const secs = diff / 1000;
uploadData.elapsed = secs.toFixed(1); uploadData.elapsed = secs.toFixed(1);
}, 75), }, 75),
start: performance.now(), start: performance.now(),
elapsed: '0' elapsed: '0'
}; };
// Start upload process // Start upload process
uploadStarted = true; uploadStarted = true;
} }
async function fetchReddit(data: SubmitData) { async function fetchReddit(data: SubmitData) {
if (!data.subreddit) return; if (!data.subreddit) return;
// Request subreddit data // Request subreddit data
const response = await fetch(`/api/reddit?subreddit=${data.subreddit}`); const response = await fetch(`/api/reddit?subreddit=${data.subreddit}`);
const mdata = (await response.json()) as APIResponse; const mdata = (await response.json()) as APIResponse;
// Ignore failed // Ignore failed
if (!mdata.success) return; if (!mdata.success) return;
const sources = mdata.results! as string[]; const sources = mdata.results! as string[];
if (sources.length === 0) return; if (sources.length === 0) return;
// Get images and automatically update // Get images and automatically update
imageURL = sources[0]; imageURL = sources[0];
posts = { posts = {
interval: setInterval(() => { interval: setInterval(() => {
uploadStarted = false; uploadStarted = false;
if (posts.index >= posts.sources.length) { if (posts.index >= posts.sources.length) {
clearInterval(posts.interval); clearInterval(posts.interval);
return; return;
} }
imageURL = posts.sources[++posts.index]; imageURL = posts.sources[++posts.index];
setTimeout(() => (uploadStarted = true), 15); setTimeout(() => (uploadStarted = true), 15);
}, 30000), }, 30000),
index: 0, index: 0,
sources sources
}; };
// Remove subreddit tag from submit data // Remove subreddit tag from submit data
delete data.subreddit; delete data.subreddit;
} }
// On client loaded // On client loaded
onMount(() => { onMount(() => {
matrix = initializeMatrix(); matrix = initializeMatrix();
}); });
</script> </script>
<h1 class="text-4xl font-bold m-5 text-center">Matrix Image Upload</h1> <h1 class="text-4xl font-bold m-5 text-center">Matrix Image Upload</h1>
<form class="grid grid-rows-5 m-1" on:submit|preventDefault={handleSubmit}> <form class="grid grid-rows-5 m-1" on:submit|preventDefault={handleSubmit}>
<div class="grid grid-cols-2"> <div class="grid grid-cols-2">
<label class="border-2 border-black border-r-0 border-b-0 pl-1" for="x">Set X coordinate:</label <label class="border-2 border-black border-r-0 border-b-0 pl-1" for="x">Set X coordinate:</label
> >
<input <input
class="border-2 border-black border-b-0 cursor-text pl-1 bg-gray-100" class="border-2 border-black border-b-0 cursor-text pl-1 bg-gray-100"
type="number" type="number"
name="x" name="x"
id="x" id="x"
min="0" min="0"
max={(matrix?.width ?? 192) - 1} max={(matrix?.width ?? 192) - 1}
step="1" step="1"
value="0" value="0"
/> />
</div> </div>
<div class="grid grid-cols-2"> <div class="grid grid-cols-2">
<label class="border-2 border-black border-r-0 border-b-0 pl-1" for="y">Set Y coordinate:</label <label class="border-2 border-black border-r-0 border-b-0 pl-1" for="y">Set Y coordinate:</label
> >
<input <input
class="border-2 border-black border-b-0 cursor-text pl-1 bg-gray-100" class="border-2 border-black border-b-0 cursor-text pl-1 bg-gray-100"
type="number" type="number"
name="y" name="y"
id="y" id="y"
min="0" min="0"
max={(matrix?.height ?? 192) - 1} max={(matrix?.height ?? 192) - 1}
step="1" step="1"
value="0" value="0"
/> />
</div> </div>
<div class="grid grid-cols-2"> <div class="grid grid-cols-2">
<label class="border-2 border-black border-r-0 border-b-0 pl-1" for="w">Set image width:</label> <label class="border-2 border-black border-r-0 border-b-0 pl-1" for="w">Set image width:</label>
<input <input
class="border-2 border-black border-b-0 cursor-text pl-1 bg-gray-100" class="border-2 border-black border-b-0 cursor-text pl-1 bg-gray-100"
type="number" type="number"
name="w" name="w"
id="w" id="w"
min="1" min="1"
max={matrix?.width ?? 192} max={matrix?.width ?? 192}
step="1" step="1"
value={matrix?.width ?? 192} value={matrix?.width ?? 192}
/> />
</div> </div>
<div class="grid grid-cols-2"> <div class="grid grid-cols-2">
<label class="border-2 border-black border-r-0 border-b-0 pl-1" for="h">Set image height:</label <label class="border-2 border-black border-r-0 border-b-0 pl-1" for="h">Set image height:</label
> >
<input <input
class="border-2 border-black border-b-0 cursor-text pl-1 bg-gray-100" class="border-2 border-black border-b-0 cursor-text pl-1 bg-gray-100"
type="number" type="number"
name="h" name="h"
id="h" id="h"
min="1" min="1"
max={matrix?.height ?? 192} max={matrix?.height ?? 192}
step="1" step="1"
value={matrix?.height ?? 192} value={matrix?.height ?? 192}
/> />
</div> </div>
<div class="grid grid-cols-2"> <div class="grid grid-cols-2">
<label class="border-2 border-black border-r-0 border-b-0 pl-1" for="image">Set an image:</label <label class="border-2 border-black border-r-0 border-b-0 pl-1" for="image">Set an image:</label
> >
<input <input
class="border-2 border-black border-b-0 bg-gray-100" class="border-2 border-black border-b-0 bg-gray-100"
type="file" type="file"
name="image" name="image"
id="image" id="image"
accept="image/*" accept="image/*"
on:change={getImage} on:change={getImage}
/> />
</div> </div>
<div class="grid grid-cols-2"> <div class="grid grid-cols-2">
<label class="border-2 border-black border-r-0 border-b-0 pl-1" for="update">Auto update:</label <label class="border-2 border-black border-r-0 border-b-0 pl-1" for="update">Auto update:</label
> >
<div class="border-2 border-black border-b-0 pl-1 bg-gray-100 w-full"> <div class="border-2 border-black border-b-0 pl-1 bg-gray-100 w-full">
<input class="w-full" type="checkbox" name="update" id="update" checked /> <input class="w-full" type="checkbox" name="update" id="update" checked />
</div> </div>
</div> </div>
<input <input
class="border-2 border-black border-b-0 hover:bg-gray-200 cursor-pointer" class="border-2 border-black border-b-0 hover:bg-gray-200 cursor-pointer"
type="submit" type="submit"
value="Upload!" value="Upload!"
/> />
<div class="grid grid-cols-2"> <div class="grid grid-cols-2">
<label class="border-2 border-black border-r-0 border-b-0 pl-1" for="subreddit" <label class="border-2 border-black border-r-0 border-b-0 pl-1" for="subreddit"
>Subreddit name:</label >Subreddit name:</label
> >
<input <input
class="border-2 border-black border-b-0 cursor-text pl-1 bg-gray-100" class="border-2 border-black border-b-0 cursor-text pl-1 bg-gray-100"
type="text" type="text"
name="subreddit" name="subreddit"
id="subreddit" id="subreddit"
/> />
</div> </div>
<input <input
class="border-2 border-black hover:bg-gray-200 cursor-pointer" class="border-2 border-black hover:bg-gray-200 cursor-pointer"
type="submit" type="submit"
value="Fetch!" value="Fetch!"
/> />
{#if imageURL} {#if imageURL}
<img class="mt-5 block ml-auto mr-auto" src={imageURL} alt="User uploaded or reddit" /> <img class="mt-5 block ml-auto mr-auto" src={imageURL} alt="User uploaded or reddit" />
{/if} {/if}
</form> </form>
{#if uploadStarted} {#if uploadStarted}
{#if submitData.subreddit} {#if submitData.subreddit}
{#await fetchReddit(submitData)} {#await fetchReddit(submitData)}
<p>Fetching subreddit data . . .</p> <p>Fetching subreddit data . . .</p>
<p>{uploadData.elapsed} seconds elapsed.</p> <p>{uploadData.elapsed} seconds elapsed.</p>
{/await} {/await}
{:else} {:else}
{#await fileAsDataURL(submitData)} {#await fileAsDataURL(submitData)}
<p>Loading image data . . .</p> <p>Loading image data . . .</p>
<p>{uploadData.elapsed} seconds elapsed.</p> <p>{uploadData.elapsed} seconds elapsed.</p>
{:then dataUrl} {:then dataUrl}
{#await sendImage(dataUrl)} {#await sendImage(dataUrl)}
<p>Sending image . . .</p> <p>Sending image . . .</p>
<p>{uploadData.elapsed} seconds elapsed.</p> <p>{uploadData.elapsed} seconds elapsed.</p>
{:then} {:then}
{#await placeImage(submitData)} {#await placeImage(submitData)}
<p>Placing image . . .</p> <p>Placing image . . .</p>
<p>{uploadData.elapsed} seconds elapsed.</p> <p>{uploadData.elapsed} seconds elapsed.</p>
{:then} {:then}
{#await updateMatrix(submitData)} {#await updateMatrix(submitData)}
<p>Updating matrix . . .</p> <p>Updating matrix . . .</p>
<p>{uploadData.elapsed} seconds elapsed.</p> <p>{uploadData.elapsed} seconds elapsed.</p>
{:then} {:then}
<p>Done!</p> <p>Done!</p>
<p>{uploadData.elapsed} seconds elapsed.</p> <p>{uploadData.elapsed} seconds elapsed.</p>
{/await} {/await}
{/await} {/await}
{/await} {/await}
{/await} {/await}
{/if} {/if}
{/if} {/if}

View File

@ -10,11 +10,13 @@
"sourceMap": true, "sourceMap": true,
"strict": true, "strict": true,
"moduleResolution": "bundler", "moduleResolution": "bundler",
"plugins": [{ "plugins": [
"name": "typescript-svelte-plugin", {
"assumeIsSvelteProject": false, "name": "typescript-svelte-plugin",
"enabled": true "assumeIsSvelteProject": false,
}] "enabled": true
}
]
} }
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
// //

View File

@ -6,5 +6,5 @@ export default defineConfig({
test: { test: {
include: ['src/**/*.{test,spec}.{js,ts}'], include: ['src/**/*.{test,spec}.{js,ts}'],
exclude: ['src/playwright'] exclude: ['src/playwright']
}, }
}); });