File size: 3,360 Bytes
3b623f5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<script>
	import { getContext } from 'svelte';
	const i18n = getContext('i18n');

	import RichTextInput from '../common/RichTextInput.svelte';
	import Spinner from '../common/Spinner.svelte';
	import Sparkles from '../icons/Sparkles.svelte';
	import SparklesSolid from '../icons/SparklesSolid.svelte';
	import Mic from '../icons/Mic.svelte';
	import VoiceRecording from '../chat/MessageInput/VoiceRecording.svelte';
	import Tooltip from '../common/Tooltip.svelte';
	import { toast } from 'svelte-sonner';

	let name = '';
	let content = '';

	let voiceInput = false;
	let loading = false;
</script>

<div class="relative flex-1 w-full h-full flex justify-center overflow-auto px-5">
	{#if loading}
		<div class=" absolute top-0 bottom-0 left-0 right-0 flex">
			<div class="m-auto">
				<Spinner />
			</div>
		</div>
	{/if}

	<div class=" w-full flex flex-col gap-2 {loading ? 'opacity-20' : ''}">
		<div class="flex-shrink-0 w-full flex justify-between items-center">
			<div class="w-full">
				<input
					class="w-full text-2xl font-medium bg-transparent outline-none"
					type="text"
					bind:value={name}
					placeholder={$i18n.t('Title')}
					required
				/>
			</div>
		</div>

		<div class=" flex-1 w-full h-full">
			<RichTextInput
				className=" input-prose-sm"
				bind:value={content}
				placeholder={$i18n.t('Write something...')}
			/>
		</div>
	</div>

	<div class="absolute bottom-0 left-0 right-0 p-5 max-w-full flex justify-end">
		<div class="flex gap-0.5 justify-end w-full">
			{#if voiceInput}
				<div class="flex-1 w-full">
					<VoiceRecording
						bind:recording={voiceInput}
						className="p-1 w-full max-w-full"
						on:cancel={() => {
							voiceInput = false;
						}}
						on:confirm={(e) => {
							const { text, filename } = e.detail;

							// url is hostname + /cache/audio/transcription/ + filename
							const url = `${window.location.origin}/cache/audio/transcription/${filename}`;

							// Open in new tab

							if (content.trim() !== '') {
								content = `${content}\n\n${text}\n\nRecording: ${url}\n\n`;
							} else {
								content = `${content}${text}\n\nRecording: ${url}\n\n`;
							}

							voiceInput = false;
						}}
					/>
				</div>
			{:else}
				<Tooltip content={$i18n.t('Voice Input')}>
					<button
						class="cursor-pointer p-2.5 flex rounded-full hover:bg-gray-100 dark:hover:bg-gray-850 transition shadow-xl"
						type="button"
						on:click={async () => {
							try {
								let stream = await navigator.mediaDevices
									.getUserMedia({ audio: true })
									.catch(function (err) {
										toast.error(
											$i18n.t(`Permission denied when accessing microphone: {{error}}`, {
												error: err
											})
										);
										return null;
									});

								if (stream) {
									voiceInput = true;
									const tracks = stream.getTracks();
									tracks.forEach((track) => track.stop());
								}
								stream = null;
							} catch {
								toast.error($i18n.t('Permission denied when accessing microphone'));
							}
						}}
					>
						<Mic className="size-4" />
					</button>
				</Tooltip>
			{/if}

			<!-- <button
				class="cursor-pointer p-2.5 flex rounded-full hover:bg-gray-100 dark:hover:bg-gray-850 transition shadow-xl"
			>
				<SparklesSolid className="size-4" />
			</button> -->
		</div>
	</div>
</div>