179 lines
6.5 KiB
Markdown
179 lines
6.5 KiB
Markdown
GitHub Copilot Instructions for This Repository
|
||
|
||
Basics: These you need to really follow!
|
||
- If you have any questions, always ask me first!
|
||
- Use Svelte 5 runes exclusively
|
||
- Declare reactive state with $state(); derive values with $derived(); run side-effect logic with $effect() etc.
|
||
- When doing client-side loading, always implement placeholders and loaders, so the UI remains responsive and layout shifts are minimized.
|
||
- Don't use placeholders and loaders for static data like heading etc.
|
||
- Never use supabse-js. I am using supabse-ssr and supabase client is located in:
|
||
- client: $props.data.supabse
|
||
- server: $locals.supabase
|
||
|
||
Do not fall back to the legacy $: label syntax or Svelte 3/4 stores! This is important!
|
||
|
||
Enforce a clean component structure
|
||
|
||
<script> comes first, followed by markup and then an optional <style> (rarely needed—prefer Tailwind).
|
||
|
||
Export component props with export let … (still valid in Svelte 5).
|
||
|
||
Keep each component focused on one visual/behavioural concern; split larger UIs into children.
|
||
|
||
Tailwind-only styling conventions
|
||
|
||
Base container: rounded-lg border border-gray-300 (or rounded-md on small items).
|
||
|
||
Absolutely no shadow-* classes.
|
||
|
||
Use p-4 or p-6 for internal padding, and gap-* utilities (not margin hacks) for spacing between children.
|
||
|
||
Prefer neutral greys (gray-50‒gray-800) and a single accent palette defined in tailwind.config.js.
|
||
|
||
HTML & accessibility
|
||
|
||
Generate semantic elements (<button>, <nav>, <main>, <section>, <label>, etc.).
|
||
|
||
Every interactive element must have an accessible name (aria-label, visible text, or title).
|
||
|
||
Do not generate tabindex gymnastics; rely on natural DOM order.
|
||
|
||
Type safety & tooling
|
||
|
||
Default to <script lang="ts"> unless the file is explicitly plain JS.
|
||
|
||
Always import types from @types/svelte or svelte where needed.
|
||
|
||
File / folder conventions
|
||
|
||
Component names are PascalCase.svelte.
|
||
|
||
Collocate tests as ComponentName.test.ts beside the component.
|
||
|
||
Put shared util functions in src/lib.
|
||
|
||
Example pattern (reference only)
|
||
|
||
svelte
|
||
Copy
|
||
Edit
|
||
<!-- copilot: follow the repo instructions above -->
|
||
<script lang="ts">
|
||
let count = $state(0);
|
||
let doubled = $derived(count * 2);
|
||
$effect(() => console.log(`count is ${count}`));
|
||
</script>
|
||
|
||
<div class="rounded-lg border border-gray-300 p-4 flex flex-col gap-4">
|
||
<button
|
||
class="rounded-md px-4 py-2 bg-blue-600 text-white"
|
||
onclick={() => count++}
|
||
aria-label="Increment counter"
|
||
>
|
||
{count}
|
||
</button>
|
||
|
||
<p>{doubled}</p>
|
||
</div>
|
||
What not to do
|
||
|
||
No inline style="" attributes.
|
||
|
||
No external CSS files unless Tailwind cannot express the rule.
|
||
|
||
No class names that imply design debt (.box, .wrapper, .container-1, etc.).
|
||
|
||
Avoid non-reactive variables; if a value affects the UI, use a rune.
|
||
|
||
NEVER $: label syntax; use $state(), $derived(), and $effect().
|
||
|
||
If you want to use supabse client in the browser, it is stored in the data
|
||
variable obtained from let { data } = $props();
|
||
|
||
Using `on:click` to listen to the click event is deprecated. Use the event attribute `onclick` instead
|
||
|
||
onsubmit|preventDefault={handleSubmit} is depracated, do not use it!
|
||
|
||
Loading session using page.server.ts is not needed as the session is already available in the locals object.
|
||
|
||
Do not use import { page } from '$app/stores'; as it is deprecated! Use instead: import { page } from '$app/state';
|
||
|
||
IMPORTANT: Always make sure that the client-side module are not importing secrets
|
||
or are running any sensritive code that could expose secrets to the client.
|
||
If any requests are needed to check sensitive infomration, create an api route and
|
||
fetch data from there instead of directly in the client-side module.
|
||
|
||
The database schema in supabase is as follows:
|
||
-- WARNING: This schema is for context only and is not meant to be run.
|
||
-- Table order and constraints may not be valid for execution.
|
||
-- WARNING: This schema is for context only and is not meant to be run.
|
||
-- Table order and constraints may not be valid for execution.
|
||
|
||
CREATE TABLE public.events (
|
||
id uuid NOT NULL DEFAULT gen_random_uuid(),
|
||
created_at timestamp with time zone NOT NULL DEFAULT now(),
|
||
created_by uuid DEFAULT auth.uid(),
|
||
name text,
|
||
date date,
|
||
section_id uuid,
|
||
email_subject text,
|
||
email_body text,
|
||
sheet_id text,
|
||
name_column numeric,
|
||
surname_column numeric,
|
||
email_column numeric,
|
||
confirmation_column numeric,
|
||
CONSTRAINT events_pkey PRIMARY KEY (id),
|
||
CONSTRAINT events_created_by_fkey FOREIGN KEY (created_by) REFERENCES auth.users(id),
|
||
CONSTRAINT events_section_id_fkey FOREIGN KEY (section_id) REFERENCES public.sections(id)
|
||
);
|
||
CREATE TABLE public.events_archived (
|
||
id uuid NOT NULL DEFAULT gen_random_uuid(),
|
||
created_at timestamp with time zone NOT NULL DEFAULT now(),
|
||
date date,
|
||
name text NOT NULL,
|
||
total_participants numeric,
|
||
scanned_participants numeric,
|
||
section_id uuid,
|
||
CONSTRAINT events_archived_pkey PRIMARY KEY (id),
|
||
CONSTRAINT events_archived_section_id_fkey FOREIGN KEY (section_id) REFERENCES public.sections(id)
|
||
);
|
||
CREATE TABLE public.participants (
|
||
id uuid NOT NULL DEFAULT gen_random_uuid(),
|
||
created_at timestamp with time zone NOT NULL DEFAULT now(),
|
||
created_by uuid DEFAULT auth.uid(),
|
||
event uuid,
|
||
name text,
|
||
surname text,
|
||
email text,
|
||
scanned boolean DEFAULT false,
|
||
scanned_at timestamp with time zone,
|
||
scanned_by uuid,
|
||
section_id uuid,
|
||
email_sent boolean DEFAULT false,
|
||
CONSTRAINT participants_pkey PRIMARY KEY (id),
|
||
CONSTRAINT participants_created_by_fkey FOREIGN KEY (created_by) REFERENCES auth.users(id),
|
||
CONSTRAINT participants_event_fkey FOREIGN KEY (event) REFERENCES public.events(id),
|
||
CONSTRAINT participants_scanned_by_fkey FOREIGN KEY (scanned_by) REFERENCES public.profiles(id),
|
||
CONSTRAINT qrcodes_scanned_by_fkey FOREIGN KEY (scanned_by) REFERENCES auth.users(id),
|
||
CONSTRAINT qrcodes_section_id_fkey FOREIGN KEY (section_id) REFERENCES public.sections(id)
|
||
);
|
||
CREATE TABLE public.profiles (
|
||
id uuid NOT NULL,
|
||
display_name text,
|
||
created_at timestamp with time zone DEFAULT now(),
|
||
updated_at timestamp with time zone DEFAULT now(),
|
||
section_id uuid,
|
||
section_position USER-DEFINED NOT NULL DEFAULT 'member'::section_posititon,
|
||
CONSTRAINT profiles_pkey PRIMARY KEY (id),
|
||
CONSTRAINT profiles_id_fkey FOREIGN KEY (id) REFERENCES auth.users(id),
|
||
CONSTRAINT profiles_section_id_fkey FOREIGN KEY (section_id) REFERENCES public.sections(id)
|
||
);
|
||
CREATE TABLE public.sections (
|
||
id uuid NOT NULL DEFAULT gen_random_uuid(),
|
||
created_at timestamp with time zone NOT NULL DEFAULT now(),
|
||
name text NOT NULL UNIQUE,
|
||
CONSTRAINT sections_pkey PRIMARY KEY (id)
|
||
);
|
||
|