turnstile.svelte RawHistoryFolder

1<script lang="ts">
2	import { onMount } from 'svelte';
3	import { fade } from 'svelte/transition';
4	import { env } from '$env/dynamic/public';
5	import type { TurnstileOptions } from '$lib/types/turnstile';
6
7	let isVerified = $state(false);
8
9	type OnVerifyCallback = (token: string) => void;
10	let { onVerify } = $props<{ onVerify: OnVerifyCallback }>();
11
12	let turnstileElement = $state<HTMLDivElement | null>(null);
13	let widgetId = '';
14
15	// Ensure site key is a string and trim any whitespace
16	const siteKey = String(env.PUBLIC_TURNSTILE_SITE_KEY ?? '').trim();
17
18	onMount(() => {
19		if (!window.turnstile) {
20			const script = document.createElement('script');
21			script.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js';
22			script.async = true;
23			script.defer = true;
24			document.head.appendChild(script);
25
26			script.onload = initTurnstile;
27		} else {
28			initTurnstile();
29		}
30
31		return () => {
32			if (widgetId) {
33				window.turnstile?.remove(widgetId);
34			}
35		};
36	});
37
38	function initTurnstile() {
39		if (!turnstileElement || !window.turnstile) return;
40
41		// Validate site key is a non-empty string
42		if (!siteKey) {
43			console.error('Turnstile site key is missing');
44			return;
45		}
46
47		const options: TurnstileOptions = {
48			sitekey: siteKey,
49			callback: (token: string) => {
50				if (typeof onVerify === 'function') {
51					onVerify(token);
52					isVerified = true;
53				} else {
54					console.error('onVerify callback is not a function');
55				}
56			},
57			'refresh-expired': 'auto',
58			size: 'compact',
59			'error-callback': (error: unknown) => {
60				console.error('Turnstile error:', error);
61				isVerified = false; // Reset verification state on error
62			}
63		};
64
65		try {
66			widgetId = window.turnstile.render(turnstileElement, options);
67
68			// Add resize handler
69			const handleResize = () => scaleTurnstileToFit();
70			window.addEventListener('resize', handleResize);
71			// Initial scale
72			scaleTurnstileToFit();
73		} catch (error) {
74			console.error('Failed to render Turnstile:', error);
75		}
76	}
77
78	function scaleTurnstileToFit() {
79		const container = turnstileElement;
80		if (!container) return;
81
82		const iframe = container.querySelector('iframe');
83		if (!iframe) return;
84
85		const containerWidth = container.offsetWidth;
86		const scale = Math.min(1, containerWidth / 300); // 300px is approximate base width
87
88		iframe.style.transform = `scale(${scale})`;
89		iframe.style.transformOrigin = 'center center';
90	}
91</script>
92
93{#if !isVerified}
94	<div class="turnstile-wrapper" transition:fade={{ duration: 300 }}>
95		<div bind:this={turnstileElement} class="turnstile-container" data-theme="light"></div>
96	</div>
97{/if}
98
99<style>
100	.turnstile-wrapper {
101		width: 100%;
102		display: flex;
103		justify-content: center;
104		align-items: center;
105		min-height: 65px; /* Approximate height for compact size */
106		overflow: hidden;
107	}
108
109	.turnstile-container {
110		display: flex;
111		justify-content: center;
112		align-items: center;
113	}
114
115	/* Handle iframe scaling */
116	:global(.turnstile-wrapper iframe) {
117		transition: transform 0.2s ease-in-out;
118	}
119</style>

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 3

Tags 8

↑↓ moveenter openesc close