(add): Reports and some corrections.

This commit is contained in:
2026-06-27 17:55:29 -04:00
parent 37bba94880
commit 9602ed52a6
17 changed files with 529 additions and 228 deletions
+14
View File
@@ -13,6 +13,8 @@ export const bS = {
green: 'px-2 py-1 bg-green-300 border border-gray-700 rounded hover:bg-green-400 cursor-pointer',
orange:
'px-2 py-1 bg-orange-300 border border-gray-700 rounded hover:bg-orange-400 cursor-pointer',
purple:
'px-2 py-1 bg-purple-300 border border-gray-700 rounded hover:bg-purple-400 cursor-pointer',
red: 'px-2 py-1 bg-red-300 border border-gray-700 rounded hover:bg-red-400 cursor-pointer'
};
@@ -26,9 +28,21 @@ export const bAS = {
'px-2 py-1 bg-green-300 border-4 border-gray-700 rounded hover:bg-green-400 cursor-pointer',
orange:
'px-2 py-1 bg-orange-300 border-4 border-gray-700 rounded hover:bg-orange-400 cursor-pointer',
purple:
'px-2 py-1 bg-purple-300 border-4 border-gray-700 rounded hover:bg-purple-400 cursor-pointer',
red: 'px-2 py-1 bg-red-300 border-4 border-gray-700 rounded hover:bg-red-400 cursor-pointer'
};
export const iS = {
normal: 'p-1 border border-black'
};
export const rBS = {
white: 'even:bg-gray-100',
blue: 'even:bg-blue-100',
yellow: 'even:bg-yellow-100',
green: 'even:bg-green-100',
orange: 'even:bg-orange-100',
purple: 'even:bg-purple-100',
red: 'even:bg-red-100'
};
+9 -6
View File
@@ -40,9 +40,10 @@ export const drawing = sqliteView('drawing', {
last_name: text('last_name'),
first_name: text('first_name'),
phone_number: text('phone_number')
}).as(sql`SELECT b.prefix, b.b_id, b.description, b.winning_ticket, t.last_name, t.first_name, t.phone_number
})
.as(sql`SELECT b.prefix, b.b_id, b.description, b.winning_ticket, t.last_name, t.first_name, t.phone_number
FROM baskets b LEFT JOIN tickets t ON b.prefix = t.prefix AND b.winning_ticket = t.t_id
ORDER BY b.prefix, b.b_id`)
ORDER BY b.prefix, b.b_id`);
export const reportByName = sqliteView('report_by_name', {
last_name: text('last_name'),
@@ -54,9 +55,10 @@ export const reportByName = sqliteView('report_by_name', {
description: text('description'),
donors: text('donors'),
winning_ticket: integer('winning_ticket')
}).as(sql`SELECT t.last_name, t.first_name, t.phone_number, t.pref, b.prefix, b.b_id, b.description, b.donors, b.winning_ticket
})
.as(sql`SELECT t.last_name, t.first_name, t.phone_number, t.pref, b.prefix, b.b_id, b.description, b.donors, b.winning_ticket
FROM baskets b LEFT JOIN tickets t ON b.prefix = t.prefix AND b.winning_ticket = t.t_id
ORDER BY t.last_name, t.first_name, t.phone_number, b.prefix, b.b_id`)
ORDER BY t.last_name, t.first_name, t.phone_number, b.prefix, b.b_id`);
export const reportByBasket = sqliteView('report_by_basket', {
prefix: text('prefix'),
@@ -68,6 +70,7 @@ export const reportByBasket = sqliteView('report_by_basket', {
first_name: text('first_name'),
phone_number: text('phone_number'),
pref: text('pref')
}).as(sql`SELECT b.prefix, b.b_id, b.description, b.donors, b.winning_ticket, t.last_name, t.first_name, t.phone_number, t.pref
})
.as(sql`SELECT b.prefix, b.b_id, b.description, b.donors, b.winning_ticket, t.last_name, t.first_name, t.phone_number, t.pref
FROM baskets b LEFT JOIN tickets t on b.prefix = t.prefix AND b.winning_ticket = t.t_id
ORDER BY b.prefix, b.b_id`)
ORDER BY b.prefix, b.b_id`);
+17 -1
View File
@@ -59,6 +59,8 @@
class={curPrefix == prefix.prefix ? bAS[prefix.color] : bS[prefix.color]}
onclick={() => (curPrefix = prefix.prefix)}>{prefix.prefix}</button
>
{:else}
<div>No Prefixes</div>
{/each}
</div>
{#if curPrefix}
@@ -71,7 +73,21 @@
<a href={resolve('/baskets/[prefix]', { prefix: curPrefix })} class={bS[pColor]}
>Baskets</a
>
<a href={resolve('/drawing/[prefix]', {prefix: curPrefix})} class="{bS[pColor]} col-span-2">Drawing Form</a>
<a
href={resolve('/drawing/[prefix]', { prefix: curPrefix })}
class="{bS[pColor]} col-span-2">Drawing Form</a
>
</div>
</div>
<div class="flex flex-col gap-1 items-center border border-black rounded">
<h2 class="text-lg font-bold">Reports:</h2>
<div class="grid grid-cols-2 gap-1 p-1 text-center">
<a href={resolve('/reports/byname/[prefix]', { prefix: curPrefix })} class={bS[pColor]}
>Winners By Name</a
>
<a href={resolve('/reports/bybasket/[prefix]', { prefix: curPrefix })} class={bS[pColor]}
>Winners By Basket</a
>
</div>
</div>
{:else}
+14 -8
View File
@@ -1,8 +1,8 @@
import { db } from "$lib/server/db";
import { baskets, drawing } from "$lib/server/db/schema";
import { getPath, getSettings } from "$lib/server/settings"
import { error, json } from "@sveltejs/kit";
import { sql } from "drizzle-orm";
import { db } from '$lib/server/db';
import { baskets, drawing } from '$lib/server/db/schema';
import { getPath, getSettings } from '$lib/server/settings';
import { error, json } from '@sveltejs/kit';
import { sql } from 'drizzle-orm';
export const GET = async () => {
const s = getSettings();
@@ -20,7 +20,7 @@ export const GET = async () => {
const data = await db.select().from(drawing).orderBy(drawing.prefix, drawing.b_id);
return json(data);
}
}
};
export const POST = async ({ request }) => {
const reqData = await request.json();
@@ -34,6 +34,12 @@ export const POST = async ({ request }) => {
});
if (!res.ok) throw error(res.status);
}
await db.insert(baskets).values(reqData).onConflictDoUpdate({target: [baskets.prefix, baskets.b_id], set: {winning_ticket: sql`EXCLUDED.winning_ticket`}});
await db
.insert(baskets)
.values(reqData)
.onConflictDoUpdate({
target: [baskets.prefix, baskets.b_id],
set: { winning_ticket: sql`EXCLUDED.winning_ticket` }
});
return json(reqData);
}
};
@@ -10,7 +10,9 @@ export const GET = async ({ params }) => {
if (s.remote_server) {
const connStr = getPath(s);
try {
const res = await fetch(`${connStr}/api/drawing/${prefix}`, {headers: {'TAM-KEY': s.remote_key}});
const res = await fetch(`${connStr}/api/drawing/${prefix}`, {
headers: { 'TAM-KEY': s.remote_key }
});
if (!res.ok) throw error(res.status);
const data = await res.json();
return json(data);
@@ -18,7 +20,11 @@ export const GET = async ({ params }) => {
return json([]);
}
} else {
const data = await db.select().from(drawing).where(eq(drawing.prefix, prefix)).orderBy(drawing.prefix, drawing.b_id);
const data = await db
.select()
.from(drawing)
.where(eq(drawing.prefix, prefix))
.orderBy(drawing.prefix, drawing.b_id);
return json(data);
}
}
};
@@ -8,13 +8,13 @@ const placeholder_data = (prefix, b_id) => {
return {
prefix,
b_id,
description: "",
description: '',
winning_ticket: 0,
last_name: "",
first_name: "",
phone_number: ""
}
}
last_name: '',
first_name: '',
phone_number: ''
};
};
export const GET = async ({ params }) => {
const [prefix, b_id] = [params.prefix, parseInt(params.b_id)];
@@ -22,23 +22,29 @@ export const GET = async ({ params }) => {
if (s.remote_server) {
const connStr = getPath(s);
try {
const res = await fetch(`${connStr}/api/drawing/${prefix}/${b_id}`, {headers: {'TAM-KEY': s.remote_key}});
const res = await fetch(`${connStr}/api/drawing/${prefix}/${b_id}`, {
headers: { 'TAM-KEY': s.remote_key }
});
if (!res.ok) throw error(res.status);
const [data] = await res.json();
if (data) {
return json(data);
} else {
return json(placeholder_data(prefix, b_id));
};
}
} catch {
return json(placeholder_data(prefix, b_id));
}
} else {
const [data] = await db.select().from(drawing).where(and(eq(drawing.prefix, prefix), eq(drawing.b_id, b_id))).orderBy(drawing.prefix, drawing.b_id);
const [data] = await db
.select()
.from(drawing)
.where(and(eq(drawing.prefix, prefix), eq(drawing.b_id, b_id)))
.orderBy(drawing.prefix, drawing.b_id);
if (data) {
return json(data);
} else {
return json(placeholder_data(prefix, b_id));
}
}
}
};
@@ -8,34 +8,44 @@ const placeholder_data = (prefix, b_id) => {
return {
prefix,
b_id,
description: "",
description: '',
winning_ticket: 0,
last_name: "",
first_name: "",
phone_number: ""
last_name: '',
first_name: '',
phone_number: ''
};
};
export const GET = async ({ params }) => {
const [prefix, id_from, id_to] = [params.prefix, parseInt(params.id_from), parseInt(params.id_to)];
const [prefix, id_from, id_to] = [
params.prefix,
parseInt(params.id_from),
parseInt(params.id_to)
];
const s = getSettings();
const rtnData = {};
for (let i = id_from; i <= id_to; i++) {
rtnData[i] = { ...placeholder_data(prefix, i) };
};
}
if (s.remote_server) {
const connStr = getPath(s);
try {
const res = await fetch(`${connStr}/api/drawing/${prefix}/${id_from}/${id_to}`, {headers: {'TAM-KEY': s.remote_key}});
const res = await fetch(`${connStr}/api/drawing/${prefix}/${id_from}/${id_to}`, {
headers: { 'TAM-KEY': s.remote_key }
});
if (!res.ok) throw error(res.status);
const data = Array.from(await res.json());
data.forEach((b) => rtnData[b.b_id] = b);
data.forEach((b) => (rtnData[b.b_id] = b));
} catch {
return json([]);
}
} else {
const data = await db.select().from(drawing).where(and(eq(drawing.prefix, prefix), between(drawing.b_id, id_from, id_to))).orderBy(drawing.prefix, drawing.b_id);
data.forEach((b) => rtnData[b.b_id] = b);
};
return json(Object.values(rtnData));
const data = await db
.select()
.from(drawing)
.where(and(eq(drawing.prefix, prefix), between(drawing.b_id, id_from, id_to)))
.orderBy(drawing.prefix, drawing.b_id);
data.forEach((b) => (rtnData[b.b_id] = b));
}
return json(Object.values(rtnData));
};
@@ -10,7 +10,9 @@ export const GET = async ({ params }) => {
if (s.remote_server) {
const connStr = getPath(s);
try {
const res = await fetch(`${connStr}/api/reports/bybasket/${prefix}`, {headers: {'TAM-KEY': s.remote_key}});
const res = await fetch(`${connStr}/api/reports/bybasket/${prefix}`, {
headers: { 'TAM-KEY': s.remote_key }
});
if (!res.ok) throw error(res.status);
const data = await res.json();
return json(data);
@@ -21,4 +23,4 @@ export const GET = async ({ params }) => {
const data = await db.select().from(reportByBasket).where(eq(reportByBasket.prefix, prefix));
return json(data);
}
}
};
@@ -10,7 +10,9 @@ export const GET = async ({ params }) => {
if (s.remote_server) {
const connStr = getPath(s);
try {
const res = await fetch(`${connStr}/api/reports/byname/${prefix}`, {headers: {'TAM-KEY': s.remote_key}});
const res = await fetch(`${connStr}/api/reports/byname/${prefix}`, {
headers: { 'TAM-KEY': s.remote_key }
});
if (!res.ok) throw error(res.status);
const data = await res.json();
return json(data);
@@ -21,4 +23,4 @@ export const GET = async ({ params }) => {
const data = await db.select().from(reportByName).where(eq(reportByName.prefix, prefix));
return json(data);
}
}
};
@@ -2,7 +2,7 @@
import { resolve } from '$app/paths';
import { afterNavigate, beforeNavigate } from '$app/navigation';
import { browser } from '$app/environment';
import { bS, bAS, iS } from '$lib/client/styles';
import { bS, bAS, iS, rBS } from '$lib/client/styles';
import HeaderBar from '$lib/client/components/HeaderBar.svelte';
import PagerBar from '$lib/client/components/PagerBar.svelte';
import CommandBar from '$lib/client/components/CommandBar.svelte';
@@ -28,7 +28,7 @@
let pager = $state({ idFrom: 0, idTo: 0 });
let items = $state([]);
let itemsLength = $derived(items.length);
let itemsLength = $derived.by(() => (items.length ? items.length : 0));
let itemsBuffer = $derived(items.filter((i) => i.changed));
const functions = {
getPage: async () => {
@@ -181,7 +181,7 @@
<tbody>
{#each items as item, idx (item.b_id)}
<tr
class="focus-within:font-bold"
class="focus-within:font-bold {rBS[prefix.color]}"
onfocusin={(e) => {
changeIdx(idx);
e.target.scrollIntoView({ block: 'center' });
@@ -2,7 +2,7 @@
import { resolve } from '$app/paths';
import { afterNavigate, beforeNavigate } from '$app/navigation';
import { browser } from '$app/environment';
import { bS, bAS, iS } from '$lib/client/styles';
import { bS, bAS, iS, rBS } from '$lib/client/styles';
import HeaderBar from '$lib/client/components/HeaderBar.svelte';
import PagerBar from '$lib/client/components/PagerBar.svelte';
import CommandBar from '$lib/client/components/CommandBar.svelte';
@@ -28,7 +28,7 @@
let pager = $state({ idFrom: 0, idTo: 0 });
let items = $state([]);
let itemsLength = $derived(items.length);
let itemsLength = $derived.by(() => (items.length ? items.length : 0));
let itemsBuffer = $derived(items.filter((i) => i.changed));
const functions = {
getPage: async () => {
@@ -159,7 +159,7 @@
<tr>
<td colspan="50">
<HeaderBar>
<div>Baskets:</div>
<div>Drawing Forms:</div>
{#each prefixes as p (p.prefix)}
<a
href={resolve('/drawing/[prefix]', { prefix: p.prefix })}
@@ -181,16 +181,14 @@
<tbody>
{#each items as item, idx (item.b_id)}
<tr
class="focus-within:font-bold"
class="focus-within:font-bold {rBS[prefix.color]}"
onfocusin={(e) => {
changeIdx(idx);
e.target.scrollIntoView({ block: 'center' });
}}
>
<td class="p-0.5 border">{item.b_id}</td>
<td class="p-0.5 border"
>{item.description}</td
>
<td class="p-0.5 border">{item.description}</td>
<td class="p-0.5 border"
><input
type="number"
@@ -201,18 +199,23 @@
const res = await fetch(`/api/tickets/${prefix.prefix}/${item.winning_ticket}`);
if (res.ok) {
const data = await res.json();
[item.last_name, item.first_name, item.phone_number] = [(data.last_name || ""), (data.first_name || ""), (data.phone_number || "")];
[item.last_name, item.first_name, item.phone_number] = [
data.last_name || '',
data.first_name || '',
data.phone_number || ''
];
}
}}
bind:value={item.winning_ticket}
/></td
>
<td class="p-0.5 border">
{item.last_name || ""}, {item.first_name || ""}: {item.phone_number || ""}
{item.last_name || ''}, {item.first_name || ''}: {item.phone_number || ''}
</td>
<td class="p-0.5 border"
><button
class={bS[prefix.color]}
tabindex="-1"
onclick={() => {
item.changed ? (item.changed = false) : (item.changed = true);
}}>{item.changed ? 'Yes' : 'No'}</button
@@ -0,0 +1,11 @@
import { getSettings } from '$lib/server/settings/index.js';
export const load = async ({ params, fetch }) => {
const prefixRes = await fetch('/api/prefixes');
const prefixes = await prefixRes.json();
const prefix = Array.from(prefixes).find((p) => p.prefix == params.prefix);
const reportRes = await fetch(`/api/reports/bybasket/${params.prefix}`);
const reportLines = await reportRes.json();
const { venue_name } = getSettings();
return { prefixes, prefix, reportLines, venueName: venue_name };
};
@@ -0,0 +1,104 @@
<script>
import { resolve } from '$app/paths';
import HeaderBar from '$lib/client/components/HeaderBar.svelte';
import { bAS, bS } from '$lib/client/styles';
let currentFilter = $state('');
let { data } = $props();
let prefix = $derived(data.prefix);
let pageTitle = $derived(`${prefix.prefix} Winners by Name | TAM`);
let filterTitle = $state('All Winners');
const headers = ['Basket ID', 'Description', 'Winning Ticket', 'Winner Name', 'Phone Number'];
let reportLines = $derived.by(() => {
if (currentFilter == 'CALL') {
return data.reportLines.filter((l) => l.pref == 'CALL');
} else if (currentFilter == 'TEXT') {
return data.reportLines.filter((l) => l.pref == 'TEXT');
} else {
return data.reportLines;
}
});
</script>
<svelte:head>
<title>{pageTitle}</title>
</svelte:head>
<table class="w-full box-border border-separate p-1">
<thead>
<tr class="print:hidden">
<td colspan="50">
<HeaderBar>
<div>By Name Reports:</div>
{#each data.prefixes as p (p.prefix)}
<a
href={resolve('/reports/byname/[prefix]', { prefix: p.prefix })}
class={p.prefix == prefix.prefix ? bAS[p.color] : bS[p.color]}>{p.prefix}</a
>
{/each}
</HeaderBar>
<div class="flex flex-row gap-1 py-1 justify-between">
<div class="flex flex-row gap-1">
<button
class={bS[prefix.color]}
onclick={() => {
currentFilter = '';
filterTitle = 'All Winners';
}}>All Preferences</button
>
<button
class={bS[prefix.color]}
onclick={() => {
currentFilter = 'CALL';
filterTitle = 'Winners Preferring a CALL';
}}>Call Preference</button
>
<button
class={bS[prefix.color]}
onclick={() => {
currentFilter = 'TEXT';
filterTitle = 'Winners Preferring a TEXT';
}}>Text Preference</button
>
</div>
<div class="flex flex-row gap-1">
<button class={bS[prefix.color]} onclick={() => window.print()}>Print</button>
</div>
</div>
</td>
</tr>
<tr>
<th colspan="50"><h1 class="text-lg text-left">{pageTitle}</h1></th>
</tr>
<tr>
<th colspan="50"><h2 class="italic text-left">{filterTitle}</h2></th>
</tr>
<tr class="text-sm">
{#each headers as header (header)}
<th class="text-left border p-0.5">{header}</th>
{/each}
</tr>
</thead>
<tbody class="text-sm">
{#each reportLines as line, idx (idx)}
<tr>
<td class="p-0.5 border">{line.b_id}</td>
<td class="p-0.5 border">{line.description || ''}</td>
<td class="p-0.5 border">{line.winning_ticket}</td>
<td class="p-0.5 border">{line.last_name || ''}, {line.first_name || ''}</td>
<td class="p-0.5 border">{line.phone_number || ''}</td>
</tr>
{/each}
</tbody>
<tfoot>
<tr>
<td colspan="50" class="text-center text-xs">{data.venueName}</td>
</tr>
<tr>
<td colspan="50" class="text-center text-xs">&copy; 2026 Ticket Auction Manager</td>
</tr>
</tfoot>
</table>
@@ -0,0 +1,11 @@
import { getSettings } from '$lib/server/settings/index.js';
export const load = async ({ params, fetch }) => {
const prefixRes = await fetch('/api/prefixes');
const prefixes = await prefixRes.json();
const prefix = Array.from(prefixes).find((p) => p.prefix == params.prefix);
const reportRes = await fetch(`/api/reports/byname/${params.prefix}`);
const reportLines = await reportRes.json();
const { venue_name } = getSettings();
return { prefixes, prefix, reportLines, venueName: venue_name };
};
@@ -0,0 +1,104 @@
<script>
import { resolve } from '$app/paths';
import HeaderBar from '$lib/client/components/HeaderBar.svelte';
import { bAS, bS } from '$lib/client/styles';
let currentFilter = $state('');
let { data } = $props();
let prefix = $derived(data.prefix);
let pageTitle = $derived(`${prefix.prefix} Winners by Name | TAM`);
let filterTitle = $state('All Winners');
const headers = ['Winner Name', 'Phone Number', 'Basket ID', 'Winning Ticket', 'Description'];
let reportLines = $derived.by(() => {
if (currentFilter == 'CALL') {
return data.reportLines.filter((l) => l.pref == 'CALL');
} else if (currentFilter == 'TEXT') {
return data.reportLines.filter((l) => l.pref == 'TEXT');
} else {
return data.reportLines;
}
});
</script>
<svelte:head>
<title>{pageTitle}</title>
</svelte:head>
<table class="w-full box-border border-separate p-1">
<thead>
<tr class="print:hidden">
<td colspan="50">
<HeaderBar>
<div>By Name Reports:</div>
{#each data.prefixes as p (p.prefix)}
<a
href={resolve('/reports/byname/[prefix]', { prefix: p.prefix })}
class={p.prefix == prefix.prefix ? bAS[p.color] : bS[p.color]}>{p.prefix}</a
>
{/each}
</HeaderBar>
<div class="flex flex-row gap-1 py-1 justify-between">
<div class="flex flex-row gap-1">
<button
class={bS[prefix.color]}
onclick={() => {
currentFilter = '';
filterTitle = 'All Winners';
}}>All Preferences</button
>
<button
class={bS[prefix.color]}
onclick={() => {
currentFilter = 'CALL';
filterTitle = 'Winners Preferring a CALL';
}}>Call Preference</button
>
<button
class={bS[prefix.color]}
onclick={() => {
currentFilter = 'TEXT';
filterTitle = 'Winners Preferring a TEXT';
}}>Text Preference</button
>
</div>
<div class="flex flex-row gap-1">
<button class={bS[prefix.color]} onclick={() => window.print()}>Print</button>
</div>
</div>
</td>
</tr>
<tr>
<th colspan="50"><h1 class="text-lg text-left">{pageTitle}</h1></th>
</tr>
<tr>
<th colspan="50"><h2 class="italic text-left">{filterTitle}</h2></th>
</tr>
<tr class="text-sm">
{#each headers as header (header)}
<th class="text-left border p-0.5">{header}</th>
{/each}
</tr>
</thead>
<tbody class="text-sm">
{#each reportLines as line, idx (idx)}
<tr>
<td class="p-0.5 border">{line.last_name || ''}, {line.first_name || ''}</td>
<td class="p-0.5 border">{line.phone_number || ''}</td>
<td class="p-0.5 border">{line.b_id}</td>
<td class="p-0.5 border">{line.winning_ticket}</td>
<td class="p-0.5 border">{line.description || ''}</td>
</tr>
{/each}
</tbody>
<tfoot>
<tr>
<td colspan="50" class="text-center text-xs">{data.venueName}</td>
</tr>
<tr>
<td colspan="50" class="text-center text-xs">&copy; 2026 Ticket Auction Manager</td>
</tr>
</tfoot>
</table>
@@ -13,6 +13,8 @@
onMount(() => {
prefixes = [...data.prefixes];
const form_prefix = document.getElementById('form_prefix');
if (form_prefix) form_prefix.select();
});
</script>
@@ -20,31 +22,31 @@
<title>{pageTitle}</title>
</svelte:head>
<div id="app_container" class="p-1">
<HeaderBar>
<a href={resolve('/settings')} class={bS.gray}>Back to Settings</a>
</HeaderBar>
<div id="app_container" class="p-1">
<h1 class="text-xl font-bold">{pageTitle}</h1>
<div class="flex flex-row gap-1 py-1 items-center">
<div class="flex flex-col gap-1">
<div>Prefix</div>
<input type="text" class={iS.normal} bind:value={editPrefix.prefix} />
<input type="text" id="form_prefix" class={iS.normal} bind:value={editPrefix.prefix} />
</div>
<div class="flex flex-col gap-1">
<div>Color</div>
<select name="prefix_color" class={iS.normal} bind:value={editPrefix.color}>
<select id="form_color" class={iS.normal} bind:value={editPrefix.color}>
<option value="white">White</option>
<option value="blue">Blue</option>
<option value="yellow">Yellow</option>
<option value="green">Green</option>
<option value="orange">Orange</option>
<option value="purple">Purple</option>
<option value="red">Red</option>
</select>
</div>
<div class="flex flex-col gap-1">
<div>Weight</div>
<input type="number" class={iS.normal} bind:value={editPrefix.weight} />
<input type="number" id="form_weight" class={iS.normal} bind:value={editPrefix.weight} />
</div>
<div class="flex flex-col gap-1">
<div>Actions</div>
@@ -59,6 +61,9 @@
});
if (req.ok) window.location.reload();
}
editPrefix.prefix = '';
const form_prefix = document.getElementById('form_prefix');
if (form_prefix) form_prefix.select();
}}>Add/Change</button
>
</div>
@@ -85,27 +90,33 @@
class={editPrefix.color == 'orange' ? bAS.orange : bS.orange}
onclick={() => (editPrefix.color = 'orange')}>Orange</button
>
<button
class={editPrefix.color == 'purple' ? bAS.purple : bS.purple}
onclick={() => (editPrefix.color = 'purple')}>Purple</button
>
<button
class={editPrefix.color == 'red' ? bAS.red : bS.red}
onclick={() => (editPrefix.color = 'red')}>Red</button
>
</div>
<table class="w-full">
<table class="w-full border-separate">
<thead class="text-left">
<tr>
<th>Prefix</th>
<th>Color</th>
<th>Weight</th>
<th>Actions</th>
<th class="border p-0.5">Prefix</th>
<th class="border p-0.5">Color</th>
<th class="border p-0.5">Weight</th>
<th class="border p-0.5">Actions</th>
</tr>
</thead>
<tbody>
{#each prefixes as prefix (prefix.prefix)}
<tr>
<td>{prefix.prefix}</td>
<td>{prefix.color.charAt(0).toUpperCase() + prefix.color.slice(1)}</td>
<td>{prefix.weight}</td>
<td>
<td class="border p-0.5">{prefix.prefix}</td>
<td class="border p-0.5"
>{prefix.color.charAt(0).toUpperCase() + prefix.color.slice(1)}</td
>
<td class="border p-0.5">{prefix.weight}</td>
<td class="border p-0.5">
<div class="flex flex-row gap-1 items-center">
<button class={bS[prefix.color]} onclick={() => (editPrefix = { ...prefix })}
>Edit</button
@@ -126,11 +137,3 @@
</tbody>
</table>
</div>
<style>
table td,
table th {
border: solid black 1px;
padding: 0.25rem;
}
</style>
@@ -2,7 +2,7 @@
import { resolve } from '$app/paths';
import { afterNavigate, beforeNavigate } from '$app/navigation';
import { browser } from '$app/environment';
import { bS, bAS, iS } from '$lib/client/styles';
import { bS, bAS, iS, rBS } from '$lib/client/styles';
import HeaderBar from '$lib/client/components/HeaderBar.svelte';
import PagerBar from '$lib/client/components/PagerBar.svelte';
import CommandBar from '$lib/client/components/CommandBar.svelte';
@@ -28,7 +28,7 @@
let pager = $state({ idFrom: 0, idTo: 0 });
let items = $state([]);
let itemsLength = $derived(items.length);
let itemsLength = $derived.by(() => (items.length ? items.length : 0));
let itemsBuffer = $derived(items.filter((i) => i.changed));
const functions = {
getPage: async () => {
@@ -181,7 +181,7 @@
<tbody>
{#each items as item, idx (item.t_id)}
<tr
class="focus-within:font-bold"
class="focus-within:font-bold {rBS[prefix.color]}"
onfocusin={(e) => {
changeIdx(idx);
e.target.scrollIntoView({ block: 'center' });