Add coloring
This commit is contained in:
@@ -30,24 +30,19 @@
|
|||||||
item.food = name
|
item.food = name
|
||||||
item.amount = parseInt(amount)
|
item.amount = parseInt(amount)
|
||||||
item.description = description
|
item.description = description
|
||||||
const [dbFood, err]: [Food[], Err] = await FoodService.Create(item)
|
const [dbFood, err]: [Food, Err] = await FoodService.Create(item)
|
||||||
name = ''
|
name = ''
|
||||||
amount = ''
|
amount = ''
|
||||||
description = ''
|
description = ''
|
||||||
per100 = ''
|
per100 = ''
|
||||||
per100Edited = false
|
per100Edited = false
|
||||||
|
|
||||||
if (dbFood.length == 0) {
|
|
||||||
toast.error('Creating food returned 0 rows')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (err) {
|
if (err) {
|
||||||
toast.error(err)
|
toast.error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
foodStore.update((food) => {
|
foodStore.update((food) => {
|
||||||
// @ts-ignore
|
food.unshift(dbFood)
|
||||||
food.unshift(dbFood[0])
|
|
||||||
return food
|
return food
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -64,7 +59,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<tr class="border-b border-gray-200 dark:border-gray-700">
|
<tr class="border-b border-gray-200 dark:border-gray-700 text-lg font-bold">
|
||||||
<th class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap bg-gray-50 dark:text-white dark:bg-gray-800"
|
<th class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap bg-gray-50 dark:text-white dark:bg-gray-800"
|
||||||
scope="row">
|
scope="row">
|
||||||
</th>
|
</th>
|
||||||
|
@@ -2,6 +2,9 @@
|
|||||||
import { type Food, FoodService } from '$lib/database/food'
|
import { type Food, FoodService } from '$lib/database/food'
|
||||||
|
|
||||||
export let item: Food
|
export let item: Food
|
||||||
|
export let energyColor: string
|
||||||
|
export let nameColor: string
|
||||||
|
|
||||||
let amount: string = item.amount.toString()
|
let amount: string = item.amount.toString()
|
||||||
let per100: string = item.per100?.toString() ?? ''
|
let per100: string = item.per100?.toString() ?? ''
|
||||||
let description: string = item.description ?? ''
|
let description: string = item.description ?? ''
|
||||||
@@ -34,12 +37,13 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<tr class="border-b border-gray-200 dark:border-gray-700">
|
<tr class="border-b border-gray-200 dark:border-gray-700 font-bold text-lg">
|
||||||
<th class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap bg-gray-50 dark:text-white dark:bg-gray-800"
|
<th class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap bg-gray-50 dark:text-white dark:bg-gray-800"
|
||||||
scope="row">
|
scope="row">
|
||||||
{item.date}
|
{item.date}
|
||||||
</th>
|
</th>
|
||||||
<td class="px-6 py-4"
|
<td class="px-6 py-4"
|
||||||
|
style="color: {nameColor}"
|
||||||
contenteditable="true"
|
contenteditable="true"
|
||||||
bind:innerText={name}
|
bind:innerText={name}
|
||||||
on:keydown={update}>
|
on:keydown={update}>
|
||||||
@@ -59,7 +63,7 @@
|
|||||||
bind:innerText={per100}
|
bind:innerText={per100}
|
||||||
on:keydown={update}>
|
on:keydown={update}>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4">
|
<td class="px-6 py-4" style="color: {energyColor}">
|
||||||
{item.energy}
|
{item.energy}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@@ -2,8 +2,43 @@
|
|||||||
import EmptyFoodComp from '$components/Food/EmptyFoodComp.svelte'
|
import EmptyFoodComp from '$components/Food/EmptyFoodComp.svelte'
|
||||||
import FoodComp from '$components/Food/FoodComp.svelte'
|
import FoodComp from '$components/Food/FoodComp.svelte'
|
||||||
import type { Food } from '$lib/database/food'
|
import type { Food } from '$lib/database/food'
|
||||||
|
import { GenerateColor } from '$lib/utils'
|
||||||
|
|
||||||
export let items: Food[] = []
|
export let items: Food[] = []
|
||||||
|
|
||||||
|
let minCal = 1e5
|
||||||
|
let maxCal = 0
|
||||||
|
for (let item of items) {
|
||||||
|
if (!item.energy) continue
|
||||||
|
if (item.energy > maxCal) maxCal = item.energy
|
||||||
|
if (item.energy < minCal) minCal = item.energy
|
||||||
|
}
|
||||||
|
|
||||||
|
const start = '#99ff99'
|
||||||
|
const end = '#ff9999'
|
||||||
|
|
||||||
|
function lerp(item: Food) {
|
||||||
|
if (!item) return start
|
||||||
|
if (!item.energy) return start
|
||||||
|
const t = (item.energy - minCal) / (maxCal - minCal)
|
||||||
|
const r = parseInt(start.slice(1, 3), 16) * (1 - t) + parseInt(end.slice(1, 3), 16) * t
|
||||||
|
const g = parseInt(start.slice(3, 5), 16) * (1 - t) + parseInt(end.slice(3, 5), 16) * t
|
||||||
|
const b = parseInt(start.slice(5, 7), 16) * (1 - t) + parseInt(end.slice(5, 7), 16) * t
|
||||||
|
return `rgb(${r}, ${g}, ${b})`
|
||||||
|
}
|
||||||
|
|
||||||
|
const itemColors: Map<string, string> = new Map<string, string>()
|
||||||
|
|
||||||
|
function getNameColor(item: Food): string {
|
||||||
|
if (!item) return GenerateColor()
|
||||||
|
if (!item.food) return GenerateColor()
|
||||||
|
if (!itemColors.has(item.food)) itemColors.set(item.food, GenerateColor())
|
||||||
|
// THERE'S NOTHING UNDEFINED HERE
|
||||||
|
// WE GOT RID OF UNDEFINED ON LINE 33
|
||||||
|
// ASSHOLE
|
||||||
|
// @ts-ignore
|
||||||
|
return itemColors.get(item.food)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -35,7 +70,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<EmptyFoodComp />
|
<EmptyFoodComp />
|
||||||
{#each items as f}
|
{#each items as f}
|
||||||
<FoodComp item="{f}" />
|
<FoodComp item="{f}" energyColor="{lerp(f)}" nameColor="{getNameColor(f)}" />
|
||||||
{/each}
|
{/each}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@@ -38,14 +38,18 @@ or strftime('%Y-%m-%d', date) = strftime('%Y-%m-%d', date('2024-06-12', '-1 day'
|
|||||||
order by date DESC;
|
order by date DESC;
|
||||||
`, [date])
|
`, [date])
|
||||||
},
|
},
|
||||||
async Create(food: Food): Promise<[Food[], Err]> {
|
async Create(food: Food): Promise<[Food, Err]> {
|
||||||
if (!food.food) return [[food], 'food.food is required']
|
if (!food.food) return [food, 'food.food is required']
|
||||||
if (!food.amount) throw [[food], 'food.amount is required']
|
if (!food.amount) throw [food, 'food.amount is required']
|
||||||
|
|
||||||
const res = await db.execute(`insert into food (food, description, amount) values ($1, $2, $3)`, [food.food, food.description, food.amount])
|
const res = await db.execute(`insert into food (food, description, amount) values ($1, $2, $3)`, [food.food, food.description, food.amount])
|
||||||
const row = await db.select<Food[]>(`select ${columns.join(', ')} from foodView where rowid = $1`, [res.lastInsertId])
|
const rows = await db.select<Food[]>(`select ${columns.join(', ')} from foodView where rowid = $1`, [res.lastInsertId])
|
||||||
|
|
||||||
return [row, null]
|
if (!rows) return [food, 'no data found']
|
||||||
|
if (rows.length == 0) return [food, 'no data found']
|
||||||
|
// Its not undefined mannnnnnnnnnnnnnnnnnnnnnnnnn............
|
||||||
|
// @ts-ignore
|
||||||
|
return [rows[0], null]
|
||||||
},
|
},
|
||||||
async GetLatestPer100(food: string): Promise<[number, Err]> {
|
async GetLatestPer100(food: string): Promise<[number, Err]> {
|
||||||
if (!food) return [-1, 'food is required']
|
if (!food) return [-1, 'food is required']
|
||||||
|
@@ -60,3 +60,52 @@ export const flyAndScale = (
|
|||||||
easing: cubicOut
|
easing: cubicOut
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Color = {
|
||||||
|
h: number
|
||||||
|
s: number
|
||||||
|
l: number
|
||||||
|
}
|
||||||
|
|
||||||
|
function ColorDistance(color1: Color, color2: Color) {
|
||||||
|
return Math.abs(color1.h - color2.h)
|
||||||
|
}
|
||||||
|
|
||||||
|
function GenerateRandomHSL(): Color {
|
||||||
|
const hue = Math.floor(Math.random() * 360)
|
||||||
|
const saturation = 70
|
||||||
|
const lightness = 60
|
||||||
|
return { h: hue, s: saturation, l: lightness }
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingColors: Color[] = []
|
||||||
|
|
||||||
|
function GenerateColor(): string {
|
||||||
|
const minDistance = 200
|
||||||
|
|
||||||
|
let newColor: Color
|
||||||
|
let isDistinct = false
|
||||||
|
let iterations = 0
|
||||||
|
while (!isDistinct) {
|
||||||
|
iterations++
|
||||||
|
if (iterations > 100) {
|
||||||
|
console.error('Failed to generate a distinct color after 100 iterations')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
newColor = GenerateRandomHSL()
|
||||||
|
isDistinct = true
|
||||||
|
|
||||||
|
for (const color of existingColors) {
|
||||||
|
if (ColorDistance(newColor, color) < minDistance) {
|
||||||
|
isDistinct = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can not reach this point without having a color generated
|
||||||
|
// @ts-ignore
|
||||||
|
return `hsl(${newColor.h}, ${newColor.s}%, ${newColor.l}%)`
|
||||||
|
}
|
||||||
|
|
||||||
|
export { GenerateColor }
|
||||||
|
Reference in New Issue
Block a user