Skip to content

Commit

Permalink
Merge pull request #432 from braden-w:feat/view-transformationRuns-fr…
Browse files Browse the repository at this point in the history
…om-recording-view

feat: include latest transformationRun in recordings view
  • Loading branch information
braden-w authored Jan 26, 2025
2 parents 5c1ef13 + 536ad11 commit 0d9edb1
Show file tree
Hide file tree
Showing 26 changed files with 685 additions and 339 deletions.
77 changes: 0 additions & 77 deletions apps/app/src/lib/components/CopyableCode.svelte

This file was deleted.

44 changes: 15 additions & 29 deletions apps/app/src/lib/components/WhisperingButton.svelte
Original file line number Diff line number Diff line change
@@ -1,39 +1,25 @@
<script lang="ts">
import { Button, type Props } from '$lib/components/ui/button/index.js';
import * as Tooltip from '$lib/components/ui/tooltip/index.js';
import { mergeProps } from 'bits-ui';
import type { Snippet } from 'svelte';
import WhisperingTooltip from './WhisperingTooltip.svelte';
import { nanoid } from 'nanoid/non-secure';
let {
id,
id = nanoid(),
children,
tooltipContent,
...restProps
}: { id?: string; tooltipContent: string | Snippet } & Props = $props();
...buttonProps
}: Props & { id?: string; tooltipContent: string | Snippet } = $props();
</script>

{#snippet tooltip()}
{#if typeof tooltipContent === 'string'}
{tooltipContent}
{:else}
{@render tooltipContent()}
{/if}
{/snippet}

<Tooltip.Provider>
<Tooltip.Root>
<Tooltip.Trigger {id}>
{#snippet child({ props: tooltipProps })}
<Button {...mergeProps(tooltipProps, restProps)}>
{@render children?.()}
<span class="sr-only">
{@render tooltip()}
</span>
</Button>
{/snippet}
</Tooltip.Trigger>
<Tooltip.Content class="max-w-xs text-center">
{@render tooltip()}
</Tooltip.Content>
</Tooltip.Root>
</Tooltip.Provider>
<WhisperingTooltip {id} {tooltipContent}>
{#snippet trigger({ tooltipProps, tooltip })}
<Button {...mergeProps(tooltipProps, buttonProps)}>
{@render children?.()}
<span class="sr-only">
{@render tooltip()}
</span>
</Button>
{/snippet}
</WhisperingTooltip>
42 changes: 42 additions & 0 deletions apps/app/src/lib/components/WhisperingTooltip.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script lang="ts">
import * as Tooltip from '$lib/components/ui/tooltip/index.js';
import { mergeProps } from 'bits-ui';
import type { Snippet } from 'svelte';
let {
id,
trigger,
tooltipContent,
...restProps
}: {
id: string;
trigger: Snippet<
[{ tooltipProps: Record<string, unknown>; tooltip: Snippet<[]> }]
>;
tooltipContent: string | Snippet;
} = $props();
</script>

{#snippet tooltip()}
{#if typeof tooltipContent === 'string'}
{tooltipContent}
{:else}
{@render tooltipContent()}
{/if}
{/snippet}

<Tooltip.Provider>
<Tooltip.Root>
<Tooltip.Trigger {id}>
{#snippet child({ props: tooltipProps })}
{@render trigger?.({
tooltipProps: mergeProps(tooltipProps, restProps),
tooltip,
})}
{/snippet}
</Tooltip.Trigger>
<Tooltip.Content class="max-w-xs text-center">
{@render tooltip()}
</Tooltip.Content>
</Tooltip.Root>
</Tooltip.Provider>
67 changes: 67 additions & 0 deletions apps/app/src/lib/components/copyable/CopyToClipboardButton.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<script lang="ts">
import WhisperingButton from '$lib/components/WhisperingButton.svelte';
import { ClipboardIcon } from '$lib/components/icons';
import {
type CopyToClipboardLabel,
useCopyTextToClipboardWithToast,
} from '$lib/query/clipboard/mutations';
import { CheckIcon } from 'lucide-svelte';
import type { Snippet } from 'svelte';
import type { Props } from '$lib/components/ui/button';
const copyTextToClipboardWithToast = useCopyTextToClipboardWithToast();
let {
label,
copyableText,
viewTransitionName,
copyIcon: providedCopyIcon,
class: className,
}: {
label: CopyToClipboardLabel;
copyableText: string;
viewTransitionName?: string;
copyIcon?: Snippet;
class?: string;
} = $props();
let hasCopied = $state(false);
$effect(() => {
if (hasCopied) {
setTimeout(() => {
hasCopied = false;
}, 2000);
}
});
</script>

<WhisperingButton
tooltipContent="Copy {label} to clipboard"
size="icon"
variant="ghost"
onclick={() =>
copyTextToClipboardWithToast.mutate(
{ label, text: copyableText },
{ onSuccess: () => (hasCopied = true) },
)}
style={viewTransitionName
? `view-transition-name: ${viewTransitionName};`
: undefined}
class={className}
>
<span class="sr-only">Copy</span>
{#if hasCopied}
<CheckIcon />
{:else}
{@render copyIcon()}
{/if}
</WhisperingButton>

{#snippet copyIcon()}
{#if providedCopyIcon}
{@render providedCopyIcon()}
{:else}
<ClipboardIcon />
{/if}
{/snippet}
49 changes: 49 additions & 0 deletions apps/app/src/lib/components/copyable/Copyable.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script lang="ts" module>
import { type VariantProps, tv } from 'tailwind-variants';
export const copyableVariants = tv({
base: 'relative whitespace-normal rounded p-4 pr-12 text-sm',
variants: {
variant: {
code: 'bg-muted text-muted-foreground font-semibold font-mono',
text: 'bg-muted text-muted-foreground',
error: 'bg-destructive/10 text-destructive',
},
},
});
export type CopyableVariants = VariantProps<
typeof copyableVariants
>['variant'];
</script>

<script lang="ts">
import { cn } from '$lib/utils';
import CopyToClipboardButton from './CopyToClipboardButton.svelte';
import { Label } from '../ui/label';
const {
label,
hideLabel,
copyableText,
variant,
}: {
label: string;
hideLabel?: boolean;
copyableText: string;
variant: CopyableVariants;
} = $props();
</script>

<div class="flex flex-col gap-2">
<Label class={cn('text-sm', hideLabel && 'sr-only')}>
{label}
</Label>
<pre class={copyableVariants({ variant })}>
{copyableText}
<CopyToClipboardButton
class="absolute right-4 top-4"
label={variant === 'code' ? 'code' : 'transcribed text'}
{copyableText}></CopyToClipboardButton>
</pre>
</div>
70 changes: 70 additions & 0 deletions apps/app/src/lib/components/copyable/CopyableTextDialog.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<script lang="ts">
import { ClipboardIcon } from '$lib/components/icons';
import { Button } from '$lib/components/ui/button';
import * as Card from '$lib/components/ui/card';
import * as Dialog from '$lib/components/ui/dialog';
import { Textarea } from '$lib/components/ui/textarea';
import { useCopyTextToClipboardWithToast } from '$lib/query/clipboard/mutations';
import { mergeProps } from 'bits-ui';
import WhisperingTooltip from '../WhisperingTooltip.svelte';
const copyTextToClipboardWithToast = useCopyTextToClipboardWithToast();
let {
id,
text,
}: {
id: string;
text: string;
} = $props();
let isDialogOpen = $state(false);
</script>

{#if text}
<Dialog.Root bind:open={isDialogOpen}>
<Dialog.Trigger {id}>
{#snippet child({ props: dialogTriggerProps })}
<WhisperingTooltip {id} tooltipContent="View Transcribed Text">
{#snippet trigger({ tooltipProps, tooltip })}
<Textarea
{...mergeProps(tooltipProps, dialogTriggerProps)}
class="h-full resize-none text-wrap text-left text-sm leading-snug hover:cursor-pointer hover:bg-accent hover:text-accent-foreground"
readonly
value={text}
style="view-transition-name: {id}"
rows={3}
/>
<span class="sr-only">
{@render tooltip()}
</span>
{/snippet}
</WhisperingTooltip>
{/snippet}
</Dialog.Trigger>
<Dialog.Content class="max-w-4xl">
<Card.Title class="text-lg">Transcribed Text</Card.Title>
<Textarea readonly value={text} rows={20} />
<Dialog.Footer>
<Button variant="outline" onclick={() => (isDialogOpen = false)}>
Close
</Button>
<Button
variant="outline"
onclick={() => {
copyTextToClipboardWithToast.mutate(
{
label: 'transcribed text',
text: text,
},
{ onSuccess: () => (isDialogOpen = false) },
);
}}
>
<ClipboardIcon class="h-4 w-4" />
Copy Text
</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>
{/if}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<DialogPrimitive.Content
bind:ref
class={cn(
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] bg-background fixed left-[50%] top-[50%] z-10 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg',
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] bg-background fixed left-[50%] top-[50%] z-10 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg max-h-[90vh] overflow-y-auto',
className,
)}
{...restProps}
Expand Down
2 changes: 1 addition & 1 deletion apps/app/src/lib/components/ui/dialog/dialog-footer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<div
bind:this={ref}
class={cn(
'flex flex-col-reverse sm:flex-row sm:justify-between gap-2',
'flex flex-col-reverse sm:flex-row sm:justify-end gap-2',
className,
)}
{...restProps}
Expand Down
Loading

0 comments on commit 0d9edb1

Please sign in to comment.