moved some stuff around and made the scores look nicer
This commit is contained in:
@@ -3,20 +3,18 @@ import { db } from '$lib/server/db';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import * as schema from '$lib/server/db/schema';
|
||||
|
||||
let testScore = 0;
|
||||
|
||||
// Emitter that emits
|
||||
export const globalEmitter = new EventEmitter();
|
||||
|
||||
//// REFERENCE CODE
|
||||
// Increment score for testing (remove ts)
|
||||
const increment = () => {
|
||||
testScore++;
|
||||
console.log('score incremented', testScore);
|
||||
globalEmitter.emit('scoreUpdate');
|
||||
};
|
||||
|
||||
// const increment = () => {
|
||||
// testScore++;
|
||||
// console.log('score incremented', testScore);
|
||||
// globalEmitter.emit('scoreUpdate');
|
||||
// };
|
||||
// Increment scores when there is an emit
|
||||
globalEmitter.on('incrementScores', increment);
|
||||
// globalEmitter.on('incrementScores', increment);
|
||||
|
||||
// For page.server.ts so that it doesnt look weird before loading
|
||||
export async function getAllInitialInfo() {
|
||||
@@ -29,11 +27,17 @@ export async function getAllInitialInfo() {
|
||||
// Get teams object from database
|
||||
export async function getTeams() {
|
||||
const allTeams = await db.select().from(schema.teamScoresView);
|
||||
for (let team in allTeams) {
|
||||
let currentTeam = allTeams[team];
|
||||
if (!currentTeam.totalPoints) {
|
||||
currentTeam.totalPoints = 0;
|
||||
}
|
||||
}
|
||||
return {
|
||||
teams: allTeams.map((team) => ({
|
||||
name: team.teamName,
|
||||
color: team.teamColor,
|
||||
points: team.totalPoints || testScore
|
||||
points: team.totalPoints
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
90
src/lib/ui/Table.svelte
Normal file
90
src/lib/ui/Table.svelte
Normal file
@@ -0,0 +1,90 @@
|
||||
<script lang="ts" generics="T extends { id: string | number }">
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
data: T[];
|
||||
header?: Snippet;
|
||||
row: Snippet<[T]>;
|
||||
maxHeight?: string;
|
||||
}
|
||||
|
||||
let { data, header, row, maxHeight = '300px' }: Props = $props();
|
||||
|
||||
let containerRef = $state<HTMLDivElement | null>(null);
|
||||
let activeId = $state<string | number | null>(null);
|
||||
|
||||
/**
|
||||
* Public function to scroll a specific row into the center of the viewport.
|
||||
* Can be called manually by the parent component.
|
||||
*/
|
||||
export function scrollToId(id: string | number) {
|
||||
if (!containerRef) return;
|
||||
|
||||
const targetRow = containerRef.querySelector(`#row-${id}`) as HTMLElement | null;
|
||||
if (targetRow) {
|
||||
// Update local state to highlight the centered row
|
||||
activeId = id;
|
||||
|
||||
// Calculate the midpoint math to center the row
|
||||
const rowOffsetTop = targetRow.offsetTop;
|
||||
const rowHeight = targetRow.offsetHeight;
|
||||
const containerHeight = containerRef.clientHeight;
|
||||
|
||||
// Target = Row position - (half of container space) + (half of row height adjustment)
|
||||
const centerScrollTarget = rowOffsetTop - containerHeight / 2 + rowHeight / 2;
|
||||
|
||||
// Using behavior: 'auto' for an instantaneous snap instead of smooth scrolling
|
||||
containerRef.scrollTo({
|
||||
top: centerScrollTarget,
|
||||
behavior: 'auto'
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div bind:this={containerRef} class="table-container" style="max-height: {maxHeight};">
|
||||
<table class="w-full table-auto">
|
||||
{#if header}
|
||||
<thead>
|
||||
<tr class="justify-content-center">{@render header()}</tr>
|
||||
</thead>
|
||||
{/if}
|
||||
|
||||
<tbody>
|
||||
{#each data as d (d.id)}
|
||||
<tr id="row-{d.id}" class="text-center" class:highlighted={d.id === activeId}>
|
||||
{@render row(d)}
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.table-container {
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
table thead {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
background: var(--ctp-mocha-base, #1e1e2e);
|
||||
}
|
||||
|
||||
table :global(th:not(.large)),
|
||||
table :global(td:not(.large)) {
|
||||
width: 1%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(2n + 1) {
|
||||
background: var(--ctp-mocha-surface1);
|
||||
}
|
||||
|
||||
tr.highlighted {
|
||||
outline: 2px solid var(--ctp-mocha-lavender, #b4befe);
|
||||
}
|
||||
</style>
|
||||
36
src/lib/ui/fitText.ts
Normal file
36
src/lib/ui/fitText.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import type { Action } from 'svelte/action';
|
||||
|
||||
export const fitText: Action<HTMLElement> = (node) => {
|
||||
const container = node.parentElement;
|
||||
|
||||
if (!container) return {};
|
||||
|
||||
function fit() {
|
||||
node.style.whiteSpace = 'nowrap';
|
||||
node.style.transformOrigin = 'top left';
|
||||
node.style.transform = 'none';
|
||||
|
||||
// Step 1: fit to height
|
||||
let size = 1;
|
||||
node.style.fontSize = size + 'px';
|
||||
while (node.scrollHeight <= container!.clientHeight) {
|
||||
size++;
|
||||
node.style.fontSize = size + 'px';
|
||||
}
|
||||
node.style.fontSize = size - 1 + 'px';
|
||||
|
||||
// Step 2: stretch width to fill container
|
||||
const scaleX = container!.clientWidth / node.scrollWidth;
|
||||
node.style.transform = `scaleX(${scaleX})`;
|
||||
}
|
||||
|
||||
const observer = new ResizeObserver(fit);
|
||||
observer.observe(container);
|
||||
fit();
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
observer.disconnect();
|
||||
}
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user