Implement food creation, such as it is
This commit is contained in:
@@ -64,8 +64,8 @@
|
||||
"windows": [
|
||||
{
|
||||
"title": "Svelte-Tauri",
|
||||
"width": 900,
|
||||
"height": 600,
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"fullscreen": false,
|
||||
"transparent": true,
|
||||
"decorations": false
|
||||
|
@@ -1,29 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { mode, ModeWatcher } from 'mode-watcher'
|
||||
import { Toaster } from 'svelte-sonner'
|
||||
|
||||
import { onMount } from 'svelte'
|
||||
import { type Food, FoodService } from '$lib/database/food'
|
||||
|
||||
let food: Food[] = []
|
||||
onMount(async () => {
|
||||
food = await FoodService.GetAll()
|
||||
})
|
||||
import Header from '$components/Header.svelte'
|
||||
import Router from '$router/Router.svelte'
|
||||
</script>
|
||||
|
||||
<ModeWatcher defaultMode="dark" />
|
||||
<Toaster theme={$mode} />
|
||||
|
||||
<div class="relative flex flex-col h-screen" data-vaul-drawer-wrapper id="page">
|
||||
<div>
|
||||
<pre>
|
||||
{#each food as f}
|
||||
{f.amount}
|
||||
{/each}
|
||||
</pre>
|
||||
</div>
|
||||
<!-- <Header />-->
|
||||
<!-- <main class="flex-1">-->
|
||||
<!-- <Router />-->
|
||||
<!-- </main>-->
|
||||
</div>
|
||||
<template>
|
||||
<Header />
|
||||
<main class="flex-1">
|
||||
<Router />
|
||||
</main>
|
||||
</template>
|
||||
|
61
src/lib/components/EmptyFoodComp.svelte
Normal file
61
src/lib/components/EmptyFoodComp.svelte
Normal file
@@ -0,0 +1,61 @@
|
||||
<script lang="ts">
|
||||
import { type Food, FoodService } from '$lib/database/food'
|
||||
import { toast } from 'svelte-sonner'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let item: Food = {
|
||||
food: '',
|
||||
amount: 0,
|
||||
description: ''
|
||||
}
|
||||
let name: string = ''
|
||||
let amount: string = ''
|
||||
let description: string = ''
|
||||
|
||||
async function update(event: KeyboardEvent & { currentTarget: (EventTarget & HTMLTableCellElement) }) {
|
||||
if (event.key == 'Enter') {
|
||||
item.food = name.trim()
|
||||
item.amount = parseInt(amount.trim())
|
||||
item.description = description.trim()
|
||||
const [food, err] = await FoodService.Create(item)
|
||||
name = ''
|
||||
amount = ''
|
||||
description = ''
|
||||
|
||||
if (err) {
|
||||
toast.error(err)
|
||||
return
|
||||
}
|
||||
dispatch('created', food)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<tr class="border-b border-gray-200 dark:border-gray-700">
|
||||
<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">
|
||||
</th>
|
||||
<td class="px-6 py-4"
|
||||
bind:innerText={name}
|
||||
contenteditable="true"
|
||||
on:keyup={update}>
|
||||
</td>
|
||||
<td class="px-6 py-4 bg-gray-50 dark:bg-gray-800"
|
||||
bind:innerText={description}
|
||||
contenteditable="true"
|
||||
on:keyup={update}>
|
||||
</td>
|
||||
<td class="px-6 py-4"
|
||||
bind:innerText={amount}
|
||||
contenteditable="true"
|
||||
on:keyup={update}>
|
||||
</td>
|
||||
<td class="px-6 py-4 bg-gray-50 dark:bg-gray-800">
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
31
src/lib/components/FoodComp.svelte
Normal file
31
src/lib/components/FoodComp.svelte
Normal file
@@ -0,0 +1,31 @@
|
||||
<script lang="ts">
|
||||
import type { Food } from '$lib/database/food'
|
||||
|
||||
export let item: Food
|
||||
|
||||
console.log(item)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<tr class="border-b border-gray-200 dark:border-gray-700">
|
||||
<th scope="row"
|
||||
class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap bg-gray-50 dark:text-white dark:bg-gray-800">
|
||||
{item.date}
|
||||
</th>
|
||||
<td class="px-6 py-4">
|
||||
{item.food}
|
||||
</td>
|
||||
<td class="px-6 py-4 bg-gray-50 dark:bg-gray-800">
|
||||
{item.description}
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
{item.amount}
|
||||
</td>
|
||||
<td class="px-6 py-4 bg-gray-50 dark:bg-gray-800">
|
||||
{item.per100}
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
{item.energy}
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
@@ -1,18 +1,44 @@
|
||||
import { db } from '$lib/database'
|
||||
import type { Err } from '$lib/types'
|
||||
|
||||
export type Food = {
|
||||
rowid: number,
|
||||
rowid?: number,
|
||||
date?: Date,
|
||||
food: string,
|
||||
description?: string,
|
||||
amount: number,
|
||||
per100: number,
|
||||
energy: number,
|
||||
per100?: number,
|
||||
energy?: number,
|
||||
}
|
||||
|
||||
const columns = ['rowid', 'date', 'food', 'description', 'amount', 'per100', 'energy']
|
||||
|
||||
const FoodService = {
|
||||
async GetAll() {
|
||||
return await db.select<Food[]>('SELECT rowid, food, amount, per100, energy FROM food ORDER BY date DESC')
|
||||
return await db.select<Food[]>(`
|
||||
select ${columns.join(', ')}
|
||||
from food
|
||||
order by date desc
|
||||
`)
|
||||
},
|
||||
async SetAll(data: Food[]) {
|
||||
async GetAllForDate(date: Date) {
|
||||
return await db.select<Food[]>(`
|
||||
select ${columns.join(', ')}
|
||||
from food
|
||||
where strftime('%Y-%m-%d', date) = strftime('%Y-%m-%d', '2024-06-12')
|
||||
or strftime('%Y-%m-%d', date) = strftime('%Y-%m-%d', date('2024-06-12', '-1 day'))
|
||||
order by date DESC;
|
||||
`, [date])
|
||||
},
|
||||
// TODO: Rework this to use Err in Go style
|
||||
async Create(food: Food): Promise<[Food, Err]> {
|
||||
if (!food.food) return [food, 'food.food 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 row = await db.select<Food>(`select ${columns.join(', ')} from food where rowid = $1`, [res.lastInsertId])
|
||||
|
||||
return [row, null]
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2,26 +2,28 @@
|
||||
// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually.
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__TAURI_INVOKE__<T>(cmd: string, args?: Record<string, unknown>): Promise<T>;
|
||||
}
|
||||
interface Window {
|
||||
__TAURI_INVOKE__<T>(cmd: string, args?: Record<string, unknown>): Promise<T>;
|
||||
}
|
||||
}
|
||||
|
||||
// Function avoids 'window not defined' in SSR
|
||||
const invoke = () => window.__TAURI_INVOKE__
|
||||
const invoke = () => window.__TAURI_INVOKE__;
|
||||
|
||||
export function helloTauri() {
|
||||
return invoke()<string>('hello_tauri')
|
||||
return invoke()<string>("hello_tauri")
|
||||
}
|
||||
|
||||
export function hash256sum(hashInput: string) {
|
||||
return invoke()<string>('hash256sum', { hashInput })
|
||||
return invoke()<string>("hash256sum", { hashInput })
|
||||
}
|
||||
|
||||
export function storeSetKey(key: string, value: string) {
|
||||
return invoke()<null>('store_set_key', { key, value })
|
||||
return invoke()<null>("store_set_key", { key,value })
|
||||
}
|
||||
|
||||
export function storeReadKey(key: string) {
|
||||
return invoke()<string | null>('store_read_key', { key })
|
||||
return invoke()<string | null>("store_read_key", { key })
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,14 +1,56 @@
|
||||
<section class="h-full flex-col flex items-center justify-center gap-y-8">
|
||||
<h1 class="text-6xl">Welcome</h1>
|
||||
<h2 class="flex items-center text-3xl [&_img]:h-12">
|
||||
This is a  
|
||||
<span>
|
||||
<img alt="svelte logo" src="/svelte_logo.svg" />
|
||||
</span>
|
||||
 - 
|
||||
<span>
|
||||
<img alt="svelte logo" src="/tauri_logo.svg" />
|
||||
</span>
|
||||
  Template
|
||||
</h2>
|
||||
</section>
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte'
|
||||
import { type Food, FoodService } from '$lib/database/food'
|
||||
import FoodComp from '$components/FoodComp.svelte'
|
||||
import EmptyFoodComp from '$components/EmptyFoodComp.svelte'
|
||||
|
||||
let food: Food[] = []
|
||||
onMount(async () => {
|
||||
food = await FoodService.GetAllForDate(new Date());
|
||||
})
|
||||
|
||||
function newFood(event: CustomEvent<Food>) {
|
||||
console.log(event)
|
||||
food.push(event.detail)
|
||||
food = food
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative flex flex-col h-screen" data-vaul-drawer-wrapper id="page">
|
||||
<div class="relative overflow-x-auto shadow-md sm:rounded-lg">
|
||||
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
|
||||
<thead class="text-xs text-gray-700 uppercase dark:text-gray-400">
|
||||
<tr>
|
||||
<th scope="col" class="px-6 py-3 bg-gray-50 dark:bg-gray-800">
|
||||
Date
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-3">
|
||||
Food
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-3 bg-gray-50 dark:bg-gray-800">
|
||||
Description
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-3">
|
||||
Amount
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-3 bg-gray-50 dark:bg-gray-800">
|
||||
Cal Per 100
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-3">
|
||||
Energy
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<EmptyFoodComp on:created={newFood}/>
|
||||
{#each food as f}
|
||||
<FoodComp item="{f}" />
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -1,2 +1,4 @@
|
||||
export const themes = ['dark', 'light'] as const
|
||||
export type Theme = (typeof themes)[number]
|
||||
|
||||
export type Err = string | null
|
||||
|
Reference in New Issue
Block a user