Skip to content

Commit

Permalink
Merge pull request #233 from braden-w:feature/whi-69-feat-prompt-for-…
Browse files Browse the repository at this point in the history
…copy-to-clipboard-when-copying-multiple

feat: prompt for copy to clipboard when copying multiple recordings
  • Loading branch information
braden-w authored Jul 31, 2024
2 parents bd39632 + aa0bd1d commit ae69f97
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 26 deletions.
16 changes: 0 additions & 16 deletions apps/app/src/lib/stores/recordings.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,22 +283,6 @@ export const recordings = Effect.gen(function* () {
descriptionClass: 'line-clamp-2',
});
}).pipe(Effect.catchAll(renderErrorAsToast), Effect.runPromise),
copyRecordingsTextById: (recordingIds: string[]) =>
Effect.gen(function* () {
const transcriptions = recordingIds
.map((id) => recordings.find((r) => r.id === id))
.filter((recording) => recording !== undefined)
.map((recording) => recording.transcribedText)
.filter((transcription) => transcription !== '');
const text = transcriptions.join('\n\n');
yield* clipboardService.setClipboardText(text);
yield* toast({
variant: 'success',
title: 'Copied transcriptions to clipboard!',
description: text,
descriptionClass: 'line-clamp-2',
});
}).pipe(Effect.catchAll(renderErrorAsToast), Effect.runPromise),
};
}).pipe(
Effect.provide(RecordingsDbServiceLiveIndexedDb),
Expand Down
109 changes: 99 additions & 10 deletions apps/app/src/routes/(config)/recordings/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<script lang="ts">
import WhisperingButton from '$lib/components/WhisperingButton.svelte';
import {
ChevronDownIcon,
ClipboardIcon,
Expand All @@ -10,21 +9,31 @@
} from '$lib/components/icons';
import { Button } from '$lib/components/ui/button';
import { Checkbox } from '$lib/components/ui/checkbox';
import * as Dialog from '$lib/components/ui/dialog';
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label';
import * as Table from '$lib/components/ui/table';
import { Textarea } from '$lib/components/ui/textarea/index.js';
import WhisperingButton from '$lib/components/WhisperingButton.svelte';
import { ClipboardService } from '$lib/services/ClipboardService';
import { ClipboardServiceDesktopLive } from '$lib/services/ClipboardServiceDesktopLive';
import { ClipboardServiceWebLive } from '$lib/services/ClipboardServiceWebLive';
import type { Recording } from '$lib/services/RecordingDbService';
import { toast } from '$lib/services/ToastService';
import { recordings } from '$lib/stores/recordings.svelte';
import { cn } from '$lib/utils';
import { createPersistedState } from '$lib/utils/createPersistedState.svelte';
import { Schema as S } from '@effect/schema';
import { FlexRender, createSvelteTable, renderComponent } from '@repo/svelte-table';
import type { ColumnDef, ColumnFilter, Updater } from '@tanstack/table-core';
import { getCoreRowModel, getFilteredRowModel, getSortedRowModel } from '@tanstack/table-core';
import { Effect } from 'effect';
import DataTableHeader from './DataTableHeader.svelte';
import RenderAudioUrl from './RenderAudioUrl.svelte';
import RowActions from './RowActions.svelte';
import TranscribedText from './TranscribedText.svelte';
import { renderErrorAsToast } from '$lib/services/renderErrorAsToast';
const columns: ColumnDef<Recording>[] = [
{
Expand Down Expand Up @@ -198,6 +207,37 @@
}
let filterQuery = $state(getInitialFilterValue());
let selectedRecordingRows = $derived(table.getFilteredSelectedRowModel().rows);
let template = $state('${transcribedText}');
let delimiter = $state('\n\n');
let isDialogOpen = $state(false);
let text = $derived.by(() => {
const transcriptions = selectedRecordingRows
.map(({ original }) => original)
.filter((recording) => recording.transcribedText !== '')
.map((recording) =>
template.replace(/\$\{(\w+)\}/g, (_, key) => {
switch (key) {
case 'id':
return recording.id;
case 'title':
return recording.title;
case 'subtitle':
return recording.subtitle;
case 'timestamp':
return recording.timestamp;
case 'transcribedText':
return recording.transcribedText;
default:
return '';
}
}),
);
const text = transcriptions.join('\n\n');
return text;
});
</script>

<svelte:head>
Expand Down Expand Up @@ -248,15 +288,64 @@
<StartTranscriptionIcon class="h-4 w-4" />
{/if}
</WhisperingButton>
<WhisperingButton
tooltipText="Copy transcribed text from selected recordings"
onclick={() =>
recordings.copyRecordingsTextById(selectedRecordingRows.map(({ id }) => id))}
variant="outline"
size="icon"
>
<ClipboardIcon class="h-4 w-4" />
</WhisperingButton>

<Dialog.Root open={isDialogOpen} onOpenChange={(v) => (isDialogOpen = v)}>
<Dialog.Trigger>
<WhisperingButton
tooltipText="Copy transcribed text from selected recordings"
variant="outline"
size="icon"
>
<ClipboardIcon class="h-4 w-4" />
</WhisperingButton>
</Dialog.Trigger>
<Dialog.Content class="sm:max-w-[425px]">
<Dialog.Header>
<Dialog.Title>Copy Transcripts</Dialog.Title>
<Dialog.Description>
Make changes to your profile here. Click save when you're done.
</Dialog.Description>
</Dialog.Header>
<div class="grid gap-4 py-4">
<div class="grid grid-cols-4 items-center gap-4">
<Label for="template" class="text-right">Template</Label>
<Input id="template" bind:value={template} class="col-span-3" />
</div>
<div class="grid grid-cols-4 items-center gap-4">
<Label for="delimiter" class="text-right">Delimiter</Label>
<Input id="delimiter" bind:value={delimiter} class="col-span-3" />
</div>
</div>
<Textarea placeholder="Preview of copied text" readonly class="h-32" value={text} />
<Dialog.Footer>
<WhisperingButton
tooltipText="Copy transcriptions"
onclick={() =>
Effect.gen(function* () {
const clipboardService = yield* ClipboardService;
yield* clipboardService.setClipboardText(text);
yield* toast({
variant: 'success',
title: 'Copied transcriptions to clipboard!',
description: text,
descriptionClass: 'line-clamp-2',
});
isDialogOpen = false;
}).pipe(
Effect.catchAll(renderErrorAsToast),
Effect.provide(
window.__TAURI__ ? ClipboardServiceDesktopLive : ClipboardServiceWebLive,
),
Effect.runPromise,
)}
type="submit"
>
Copy Transcriptions
</WhisperingButton>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>

<WhisperingButton
tooltipText="Delete selected recordings"
variant="outline"
Expand Down

0 comments on commit ae69f97

Please sign in to comment.