diff --git a/.svelte-kit/generated/client/app.js b/.svelte-kit/generated/client/app.js
index 18faa68c..99133679 100644
--- a/.svelte-kit/generated/client/app.js
+++ b/.svelte-kit/generated/client/app.js
@@ -12,7 +12,8 @@ export const nodes = [
() => import('./nodes/8'),
() => import('./nodes/9'),
() => import('./nodes/10'),
- () => import('./nodes/11')
+ () => import('./nodes/11'),
+ () => import('./nodes/12')
];
export const server_loads = [0];
@@ -24,8 +25,9 @@ export const dictionary = {
"/notifications": [~7],
"/profile": [8],
"/training": [~9],
- "/users": [~10],
- "/users/[id]": [~11],
+ "/training/[id]": [~10],
+ "/users": [~11],
+ "/users/[id]": [~12],
"/[site]": [~4,[2]]
};
diff --git a/.svelte-kit/generated/server/internal.js b/.svelte-kit/generated/server/internal.js
index 95737441..e6c7ce81 100644
--- a/.svelte-kit/generated/server/internal.js
+++ b/.svelte-kit/generated/server/internal.js
@@ -24,7 +24,7 @@ export const options = {
app: ({ head, body, assets, nonce, env }) => "\n\n
\n \n \n \n \n " + head + "\n \n \n " + body + "
\n \n\n",
error: ({ status, message }) => "\n\n\t\n\t\t \n\t\t" + message + " \n\n\t\t\n\t\n\t\n\t\t\n\t\t\t
" + status + " \n\t\t\t
\n\t\t\t\t
" + message + " \n\t\t\t\n\t\t
\n\t\n\n"
},
- version_hash: "1mkjc4f"
+ version_hash: "n9d9oa"
};
export async function get_hooks() {
diff --git a/.svelte-kit/non-ambient.d.ts b/.svelte-kit/non-ambient.d.ts
index f853893b..c2924641 100644
--- a/.svelte-kit/non-ambient.d.ts
+++ b/.svelte-kit/non-ambient.d.ts
@@ -27,9 +27,10 @@ export {};
declare module "$app/types" {
export interface AppTypes {
- RouteId(): "/" | "/api" | "/api/darkmode" | "/api/notifications" | "/api/notifications/[id]" | "/api/sso" | "/api/sso/exchange" | "/login" | "/logout" | "/notifications" | "/profile" | "/training" | "/users" | "/users/[id]" | "/[site]";
+ RouteId(): "/" | "/api" | "/api/darkmode" | "/api/notifications" | "/api/notifications/[id]" | "/api/sso" | "/api/sso/exchange" | "/login" | "/logout" | "/notifications" | "/profile" | "/training" | "/training/[id]" | "/users" | "/users/[id]" | "/[site]";
RouteParams(): {
"/api/notifications/[id]": { id: string };
+ "/training/[id]": { id: string };
"/users/[id]": { id: string };
"/[site]": { site: string }
};
@@ -45,12 +46,13 @@ declare module "$app/types" {
"/logout": Record;
"/notifications": Record;
"/profile": Record;
- "/training": Record;
+ "/training": { id?: string };
+ "/training/[id]": { id: string };
"/users": { id?: string };
"/users/[id]": { id: string };
"/[site]": { site: string }
};
- Pathname(): "/" | "/api/darkmode" | "/api/notifications" | `/api/notifications/${string}` & {} | "/api/sso/exchange" | "/login" | "/logout" | "/notifications" | "/profile" | "/training" | "/users" | `/users/${string}` & {} | `/${string}` & {};
+ Pathname(): "/" | "/api/darkmode" | "/api/notifications" | `/api/notifications/${string}` & {} | "/api/sso/exchange" | "/login" | "/logout" | "/notifications" | "/profile" | "/training" | `/training/${string}` & {} | "/users" | `/users/${string}` & {} | `/${string}` & {};
ResolvedPathname(): `${"" | `/${string}`}${ReturnType}`;
Asset(): string & {};
}
diff --git a/.svelte-kit/types/route_meta_data.json b/.svelte-kit/types/route_meta_data.json
index aba4d41a..11473b2d 100644
--- a/.svelte-kit/types/route_meta_data.json
+++ b/.svelte-kit/types/route_meta_data.json
@@ -34,6 +34,10 @@
"src/routes/training/+page.server.ts",
"src/routes/+layout.server.ts"
],
+ "/training/[id]": [
+ "src/routes/training/[id]/+page.server.ts",
+ "src/routes/+layout.server.ts"
+ ],
"/users": [
"src/routes/users/+page.server.ts",
"src/routes/+layout.server.ts"
diff --git a/.svelte-kit/types/src/routes/$types.d.ts b/.svelte-kit/types/src/routes/$types.d.ts
index 25f82e5e..6391558a 100644
--- a/.svelte-kit/types/src/routes/$types.d.ts
+++ b/.svelte-kit/types/src/routes/$types.d.ts
@@ -12,7 +12,7 @@ type EnsureDefined = T extends null | undefined ? {} : T;
type OptionalUnion, A extends keyof U = U extends U ? keyof U : never> = U extends unknown ? { [P in Exclude]?: never } & U : never;
export type Snapshot = Kit.Snapshot;
type PageParentData = EnsureDefined;
-type LayoutRouteId = RouteId | "/" | "/[site]" | "/login" | "/logout" | "/notifications" | "/profile" | "/training" | "/users" | "/users/[id]" | null
+type LayoutRouteId = RouteId | "/" | "/[site]" | "/login" | "/logout" | "/notifications" | "/profile" | "/training" | "/training/[id]" | "/users" | "/users/[id]" | null
type LayoutParams = RouteParams & { site?: string; id?: string }
type LayoutServerParentData = EnsureDefined<{}>;
type LayoutParentData = EnsureDefined<{}>;
diff --git a/src/routes/training/+page.server.ts b/src/routes/training/+page.server.ts
index c397f5c2..334cf203 100644
--- a/src/routes/training/+page.server.ts
+++ b/src/routes/training/+page.server.ts
@@ -9,8 +9,10 @@ type TrainingVideo = {
videoUrl: string;
};
-const VIDEO_COLLECTION = 'year';
-const VIDEO_FIELD = 'Media';
+const VIDEO_COLLECTION = 'media';
+const VIDEO_LINK_FIELD = 'Link';
+const VIDEO_FILE_FIELD = 'Media';
+const VIDEO_TITLE_FIELD = 'Title';
export const load: PageServerLoad = async ({ locals }) => {
const user = locals.user;
@@ -27,14 +29,16 @@ export const load: PageServerLoad = async ({ locals }) => {
}
const videos: TrainingVideo[] = records.map((record: any) => {
- const fileName = record[VIDEO_FIELD];
- const videoUrl = fileName
- ? locals.pb.files.getUrl(record, fileName)
- : '';
+ let videoUrl = (record[VIDEO_LINK_FIELD] as string) ?? '';
+
+ // Fallback: if there is no link but there is a file, build a file URL
+ if (!videoUrl && record[VIDEO_FILE_FIELD]) {
+ videoUrl = locals.pb.files.getUrl(record, record[VIDEO_FILE_FIELD]);
+ }
return {
id: record.id as string,
- title: (record.title as string) ?? 'Untitled video',
+ title: (record[VIDEO_TITLE_FIELD] as string) ?? (record.title as string) ?? 'Untitled video',
description: (record.description as string) ?? null,
created: record.created as string,
videoUrl
@@ -67,7 +71,7 @@ export const actions: Actions = {
const title = String(formData.get('title') ?? '').trim();
const description = String(formData.get('description') ?? '').trim();
- const file = formData.get('video');
+ const link = String(formData.get('link') ?? '').trim();
if (!title) {
return fail(400, {
@@ -76,10 +80,10 @@ export const actions: Actions = {
});
}
- if (!(file instanceof File)) {
+ if (!link) {
return fail(400, {
- error: 'Please choose a video file to upload.',
- values: { title, description }
+ error: 'YouTube link is required.',
+ values: { title, description, link }
});
}
@@ -88,7 +92,7 @@ export const actions: Actions = {
if (description) {
createData.set('description', description);
}
- createData.set(VIDEO_FIELD, file);
+ createData.set(VIDEO_LINK_FIELD, link);
try {
await locals.pb.collection(VIDEO_COLLECTION).create(createData);
diff --git a/src/routes/training/+page.svelte b/src/routes/training/+page.svelte
index 39ff305d..325dd8a5 100644
--- a/src/routes/training/+page.svelte
+++ b/src/routes/training/+page.svelte
@@ -16,6 +16,7 @@
values?: {
title?: string;
description?: string;
+ link?: string;
};
} | null;
@@ -34,33 +35,72 @@
year: d.getFullYear() !== new Date().getFullYear() ? 'numeric' : undefined
});
}
+
+ function toEmbedUrl(url: string) {
+ if (!url) return '';
+
+ try {
+ const u = new URL(url);
+
+ // Short youtu.be/
+ if (u.hostname === 'youtu.be') {
+ return `https://www.youtube.com/embed${u.pathname}`;
+ }
+
+ // www.youtube.com/watch?v= or youtube.com/watch?v=
+ if (u.hostname.includes('youtube.com')) {
+ if (u.pathname === '/watch' && u.searchParams.get('v')) {
+ const id = u.searchParams.get('v');
+ return `https://www.youtube.com/embed/${id}`;
+ }
+
+ // /embed/ already in embed form
+ if (u.pathname.startsWith('/embed/')) {
+ return url;
+ }
+
+ // Shorts: /shorts/
+ if (u.pathname.startsWith('/shorts/')) {
+ const id = u.pathname.split('/')[2];
+ if (id) {
+ return `https://www.youtube.com/embed/${id}`;
+ }
+ }
+ }
+ } catch {
+ // fall through to raw url
+ }
+
+ return url;
+ }
Training — Base
-
-
- ← Base
-
+
+
+
+ ← Base
+
-
-
Training
-
+
+
Training
+
- {#if canUpload}
-
+ {#if canUpload}
+
- Upload training video
- Add a new video for your team.
+ Add training video
+ Add a new YouTube video for your team.
{#if form?.error}
{form.error}
{/if}
-