Skip to content

Commit 8d3fb7e

Browse files
committed
A little more hacking on the restrictions table
1 parent 61114bd commit 8d3fb7e

File tree

11 files changed

+192
-61
lines changed

11 files changed

+192
-61
lines changed

src/ambient.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
type RestrictionFilters = {
22
areas: string[];
3+
airport: string;
4+
includeIncoming: boolean;
35
};

src/lib/Badge.svelte

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script lang="ts">
2+
const { classes, children } = $props<{classes: string[]; children: any }>();
3+
</script>
4+
5+
<div class="rounded-md px-2 py-1 text-xs font-medium {classes.join(' ')}">
6+
{@render children()}
7+
</div>

src/lib/server/db/schema.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
1+
import { numeric, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
22

33
export const restriction = pgTable('restrictions', {
44
id: uuid('id').primaryKey().defaultRandom(),
@@ -8,6 +8,7 @@ export const restriction = pgTable('restrictions', {
88
to: text('to'),
99
restriction: text('restriction'),
1010
notes: text('notes'),
11+
priority: numeric('priority').default('0'),
1112
validAt: timestamp('valid_at').defaultNow(),
1213
validUntil: timestamp('valid_until'),
1314
createdAt: timestamp('created_at').defaultNow()

src/lib/state.svelte.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
export const restrictionFilters: RestrictionFilters = $state({
2-
areas: []
2+
areas: [],
3+
airport: '',
4+
includeIncoming: false,
5+
incomingLessEmphasis: false
36
});

src/routes/+layout.svelte

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,30 @@
88
<div class="flex min-h-screen flex-col">
99
<!-- Navbar -->
1010
<nav
11-
class="flex h-16 w-full items-center justify-between bg-gray-700 px-4 shadow-md dark:bg-gray-900"
11+
class="flex h-16 w-full items-center justify-between bg-zinc-700 px-4 shadow-md dark:bg-zinc-900"
1212
>
1313
<a href="/">
14-
<div class="flex gap-x-2 items-center text-xl font-medium text-white hover:text-gray-200">
14+
<div class="flex gap-x-2 items-center text-xl font-medium text-white hover:text-zinc-200">
1515
<div class="w-32"><IndyLogo/></div><div>Controller Tools</div>
1616
</div>
1717
</a>
1818
<ul
19-
class="flex list-none flex-row space-x-2 text-white hover:text-gray-200"
19+
class="flex list-none flex-row space-x-2 text-white hover:text-zinc-200"
2020
>
2121
<li><a href="/restrictions">Restrictions</a></li>
2222
</ul>
2323
</nav>
2424

2525
<!-- Main Content Area -->
26-
<div class="flex-grow bg-gray-50 p-6 dark:bg-gray-800">
26+
<div class="flex-grow bg-zinc-50 p-6 dark:bg-zinc-800">
2727
{@render children()}
2828
</div>
2929

3030
<!-- Footer -->
3131
<footer
32-
class="flex w-full flex-col items-center justify-center bg-gray-700 py-4 dark:bg-gray-900"
32+
class="flex w-full flex-col items-center justify-center bg-zinc-700 py-4 dark:bg-zinc-900"
3333
>
34-
<span class="p-2 text-center text-sm text-gray-300 dark:text-gray-400">
34+
<span class="p-2 text-center text-sm text-zinc-300 dark:text-zinc-400">
3535
This site is not affiliated with the Federal Aviation Administration or
3636
any governing aviation body. All content is approved only for use on the
3737
VATSIM network.
@@ -41,6 +41,6 @@
4141

4242
<style>
4343
:global(body) {
44-
@apply bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-200;
44+
@apply bg-zinc-100 text-zinc-800 dark:bg-zinc-900 dark:text-zinc-200;
4545
}
4646
</style>
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import { db } from '$lib/server/db';
22
import { restriction } from '$lib/server/db/schema';
33
import { json } from '@sveltejs/kit';
4+
import { asc, desc, eq } from 'drizzle-orm';
45

56
export async function GET() {
6-
const restrictions = await db.select().from(restriction).orderBy(restriction.airport, 'asc');
7+
const restrictions = await db
8+
.select()
9+
.from(restriction)
10+
// .where(eq(restriction.airport, 'AGC'))
11+
.orderBy(asc(restriction.airport), desc(restriction.priority));
712

813
return json(restrictions);
914
}
Lines changed: 13 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<script lang="ts">
22
import RestrictionRow from './RestrictionRow.svelte';
33
import { restrictionFilters } from '$lib/state.svelte';
4+
import RestrictionSection from './RestrictionSection.svelte';
5+
import FilterPanel from './FilterPanel.svelte';
46
57
const { data } = $props();
68
@@ -13,9 +15,15 @@
1315
map.set(airport, []);
1416
}
1517
16-
if (restrictionFilters.areas.length === 0
17-
|| (restrictionFilters.areas.includes(restriction.to)
18-
|| restrictionFilters.areas.includes(restriction.from))) {
18+
const noAreaSelected = restrictionFilters.areas.length === 0;
19+
const searchIsEmpty = restrictionFilters.airport === '';
20+
const areaMatches = restrictionFilters.areas.includes(restriction.from) || (restrictionFilters.includeIncoming && restrictionFilters.areas.includes(restriction.to));
21+
const searchMatches = restriction.airport.toLowerCase().includes(restrictionFilters.airport.toLowerCase());
22+
23+
const isAreaMatch = noAreaSelected || areaMatches;
24+
const isSearchMatch = searchMatches || searchIsEmpty;
25+
26+
if (isAreaMatch && isSearchMatch) {
1927
map.get(airport).push(restriction);
2028
}
2129
});
@@ -29,53 +37,14 @@
2937
3038
return map;
3139
});
32-
33-
const areas = [
34-
'Area 1',
35-
'Area 2',
36-
'Area 3',
37-
'Area 4',
38-
'Area 5',
39-
'Area 6',
40-
'Area 7'
41-
];
42-
43-
function toggleAreaFilter(area: string) {
44-
if (restrictionFilters.areas.includes(area)) {
45-
restrictionFilters.areas = restrictionFilters.areas.filter(a => a !== area);
46-
} else {
47-
restrictionFilters.areas.push(area);
48-
}
49-
}
5040
</script>
5141

5242
<svelte:head>
5343
<title>ICCT - Restrictions</title>
5444
</svelte:head>
55-
<h2>Filters</h2>
56-
<div class="flex gap-2">
57-
{#each areas.filter((a) => a && a.includes('Area')) as area}
58-
<button class="px-2 py-1 rounded-md border border-b-zinc-200"
59-
class:bg-zinc-200={restrictionFilters.areas.includes(area)}
60-
onclick="{() => toggleAreaFilter(area)}">{area}</button>
61-
{/each}
62-
</div>
45+
<FilterPanel />
6346
<div class="w-full">
6447
{#each restrictions as [airport, r]}
65-
<div class="w-full flex mb-2 p-2">
66-
<div class="w-32 text-left mr-4 font-medium border rounded-md p-2 bg-gray-700 text-white">{airport}</div>
67-
<div class="flex-grow flex flex-col">
68-
<div class="flex border-b border-b-zinc-400 font-medium">
69-
<div class="w-5/12">Route</div>
70-
<div class="w-1/12">From</div>
71-
<div class="w-1/12">To</div>
72-
<div class="w-3/12">Restriction</div>
73-
<div class="w-2/12">Notes</div>
74-
</div>
75-
{#each r as restriction}
76-
<RestrictionRow {restriction} />
77-
{/each}
78-
</div>
79-
</div>
48+
<RestrictionSection {airport} restrictions={r} />
8049
{/each}
8150
</div>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<script lang="ts">
2+
import Badge from '$lib/Badge.svelte';
3+
4+
let { label } = $props<{label: string}>()
5+
6+
const areaClassesMap: Record<string, string[]> = {
7+
'Area 1': ['text-red-500', 'bg-red-100', 'border-red-500', 'dark:text-red-300', 'dark:bg-red-700', 'dark:border-red-600'],
8+
'Area 2': ['text-yellow-500', 'bg-yellow-100', 'border-yellow-500', 'dark:text-yellow-300', 'dark:bg-yellow-700', 'dark:border-yellow-600'],
9+
'Area 3': ['text-green-500', 'bg-green-100', 'border-green-500', 'dark:text-green-300', 'dark:bg-green-700', 'dark:border-green-600'],
10+
'Area 4': ['text-blue-500', 'bg-blue-100', 'border-blue-500', 'dark:text-blue-300', 'dark:bg-blue-700', 'dark:border-blue-600'],
11+
'Area 5': ['text-indigo-500', 'bg-indigo-100', 'border-indigo-500', 'dark:text-indigo-300', 'dark:bg-indigo-700', 'dark:border-indigo-600'],
12+
'Area 6': ['text-purple-500', 'bg-purple-100', 'border-purple-500', 'dark:text-purple-300', 'dark:bg-purple-700', 'dark:border-purple-600'],
13+
'Area 7': ['text-pink-500', 'bg-pink-100', 'border-pink-500', 'dark:text-pink-300', 'dark:bg-pink-700', 'dark:border-pink-600'],
14+
'Area 8': ['text-gray-500', 'bg-gray-100', 'border-gray-500', 'dark:text-gray-300', 'dark:bg-gray-700', 'dark:border-gray-600'],
15+
}
16+
17+
const defaultAreaClasses = ['text-zinc-500','bg-zinc-100', 'border-zinc-500'];
18+
</script>
19+
20+
<Badge classes={areaClassesMap[label] || defaultAreaClasses}>{label}</Badge>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<script lang="ts">
2+
import { restrictionFilters } from '$lib/state.svelte.js';
3+
4+
5+
const areas = [
6+
'Area 1',
7+
'Area 2',
8+
'Area 3',
9+
'Area 4',
10+
'Area 5',
11+
'Area 6',
12+
'Area 7'
13+
];
14+
15+
function toggleAreaFilter(area: string) {
16+
if (restrictionFilters.areas.includes(area)) {
17+
restrictionFilters.areas = restrictionFilters.areas.filter(a => a !== area);
18+
} else {
19+
restrictionFilters.areas.push(area);
20+
}
21+
}
22+
</script>
23+
24+
<div class="rounded-md lg:border lg:p-4 lg:dark:border-zinc-700 flex flex-col">
25+
<div class="py-2 lg:px-2">
26+
<input type="text" id="filter"
27+
class="w-full rounded-md border border-zinc-300 p-3 text-zinc-700 dark:bg-zinc-700 dark:text-zinc-200"
28+
placeholder="Search for Airport..." bind:value={restrictionFilters.airport}>
29+
</div>
30+
<div class="flex flex-col lg:p-2">
31+
<h2 class="text-lg font-medium">Area Filters</h2>
32+
<div class="flex gap-2">
33+
{#each areas as area}
34+
<button class="px-1 lg:px-2 py-1 text-sm lg:text-base rounded-md border dark:border-zinc-700 dark:text-zinc-200"
35+
class:bg-zinc-200={restrictionFilters.areas.includes(area)}
36+
class:dark:bg-zinc-700={restrictionFilters.areas.includes(area)}
37+
onclick="{() => toggleAreaFilter(area)}">{area}</button>
38+
{/each}
39+
</div>
40+
</div>
41+
<div class="flex py-2 lg:px-2">
42+
<input type="checkbox" id="includeIncoming" bind:checked={restrictionFilters.includeIncoming}>
43+
<label for="includeIncoming" class="text-sm pl-2">Include Incoming Restrictions</label>
44+
</div>
45+
</div>
Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,53 @@
11
<script lang="ts">
2-
const { restriction }: { restriction: any} = $props()
2+
import Badge from '$lib/Badge.svelte';
3+
import AreaBadge from './AreaBadge.svelte';
4+
5+
const { route, restrictions } = $props();
6+
7+
const defaultTextColor = 'text-zinc-100';
8+
const defaultBackgroundColor = 'bg-zinc-900';
39
</script>
410

5-
<div class="flex border-b border-b-zinc-200 last:border-0 text-sm">
6-
<div class="w-5/12">{restriction.route}</div>
7-
<div class="w-1/12">{restriction.from}</div>
8-
<div class="w-1/12">{restriction.to}</div>
9-
<div class="w-3/12">{restriction.restriction}</div>
10-
<div class="w-2/12">{restriction.notes}</div>
11+
<div class="flex flex-col lg:flex-row border-b border-b-zinc-300 dark:border-b-zinc-500 lg:py-1 last:border-0 text-sm">
12+
<!-- Route Header -->
13+
<div class="w-full lg:w-4/12 mb-2 lg:mb-0 text-zinc-700 dark:text-white lg:text-black flex">
14+
<span class="block lg:hidden font-bold">Route</span>
15+
{route}
16+
</div>
17+
18+
<!-- Restrictions Data -->
19+
<div class="flex flex-col flex-grow space-y-2">
20+
{#each restrictions as restriction}
21+
<div class="flex flex-col lg:flex-row lg:gap-x-2 space-y-2 lg:space-y-0">
22+
<!-- From Header -->
23+
24+
<div class="w-full lg:w-1/12">
25+
{#if restriction.from}
26+
<AreaBadge label={restriction.from} />
27+
{/if}
28+
</div>
29+
30+
<!-- To Header -->
31+
32+
<div class="w-full lg:w-1/12">
33+
{#if restriction.to}
34+
<AreaBadge label={restriction.to} />
35+
{/if}
36+
</div>
37+
38+
39+
<!-- Restriction Header -->
40+
<div class="w-full lg:w-3/12 flex flex-col justify-center">
41+
<span class="block lg:hidden font-bold">Restriction</span>
42+
{restriction.restriction}
43+
</div>
44+
45+
<!-- Notes Header -->
46+
<div class="w-full lg:w-3/12 flex font-light flex-col justify-center">
47+
<span class="block lg:hidden font-bold">Notes</span>
48+
{restriction.notes}
49+
</div>
50+
</div>
51+
{/each}
52+
</div>
1153
</div>

0 commit comments

Comments
 (0)