Skip to content

Commit c47b43c

Browse files
authored
Editabe transcript view (#776)
1 parent 133cad0 commit c47b43c

File tree

22 files changed

+379
-70
lines changed

22 files changed

+379
-70
lines changed

apps/desktop/src/components/right-panel/views/legacy/base.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useQuery } from "@tanstack/react-query";
22
import { writeText } from "@tauri-apps/plugin-clipboard-manager";
3-
import { ClipboardCopyIcon, FileAudioIcon } from "lucide-react";
4-
import React from "react";
3+
import { CheckIcon, ClipboardCopyIcon, FileAudioIcon, PencilIcon } from "lucide-react";
4+
import React, { useState } from "react";
55

66
import { commands as miscCommands } from "@hypr/plugin-misc";
77
import { Button } from "@hypr/ui/components/ui/button";
@@ -13,14 +13,11 @@ import { useTranscript } from "./useTranscript";
1313
import { useTranscriptWidget } from "./useTranscriptWidget";
1414

1515
export interface TranscriptBaseProps {
16-
onSizeToggle?: () => void;
17-
sizeToggleButton: React.ReactNode;
1816
WrapperComponent: React.ComponentType<any>;
1917
wrapperProps?: Partial<any>;
2018
}
2119

2220
export const TranscriptBase: React.FC<TranscriptBaseProps> = ({
23-
sizeToggleButton,
2421
WrapperComponent,
2522
wrapperProps = {},
2623
}) => {
@@ -29,6 +26,8 @@ export const TranscriptBase: React.FC<TranscriptBaseProps> = ({
2926
const { showEmptyMessage, isEnhanced, hasTranscript } = useTranscriptWidget(sessionId);
3027
const { timeline } = useTranscript(sessionId);
3128

29+
const [editing, setEditing] = useState(false);
30+
3231
const handleCopyAll = () => {
3332
if (timeline && timeline.items && timeline.items.length > 0) {
3433
const transcriptText = timeline.items.map((item) => item.text).join("\n");
@@ -94,12 +93,16 @@ export const TranscriptBase: React.FC<TranscriptBaseProps> = ({
9493
</Tooltip>
9594
</TooltipProvider>
9695
),
97-
sizeToggleButton,
96+
<Button variant="ghost" size="icon" className="p-0" onClick={() => setEditing(!editing)}>
97+
{editing
98+
? <CheckIcon size={16} className="text-black" />
99+
: <PencilIcon size={16} className="text-black" />}
100+
</Button>,
98101
].filter(Boolean)}
99102
/>
100103
</div>
101104

102-
{sessionId && <Transcript sessionId={sessionId} />}
105+
{sessionId && <Transcript sessionId={sessionId} editing={editing} />}
103106

104107
{!sessionId && (
105108
<div className="absolute inset-0 backdrop-blur-sm bg-white/50 flex items-center justify-center">

apps/desktop/src/components/right-panel/views/legacy/index.tsx

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,10 @@
1-
import { Minimize2Icon } from "lucide-react";
2-
3-
import { Button } from "@hypr/ui/components/ui/button";
41
import { WidgetFullSize, WidgetFullSizeWrapper } from "./ui";
52

63
import { TranscriptBase } from "./base";
74

85
const TranscriptFull: WidgetFullSize = ({ queryClient, onMinimize }) => {
9-
const minimizeButton = (
10-
<Button key="minimize" variant="ghost" size="icon" onClick={onMinimize}>
11-
<Minimize2Icon className="h-4 w-4 text-black" />
12-
</Button>
13-
);
14-
156
return (
167
<TranscriptBase
17-
sizeToggleButton={minimizeButton}
188
WrapperComponent={WidgetFullSizeWrapper}
199
wrapperProps={{ queryClient, onMinimize }}
2010
/>

apps/desktop/src/components/right-panel/views/legacy/transcript.tsx

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { EarIcon, Loader2Icon } from "lucide-react";
22
import { useEffect, useRef } from "react";
33

4+
import TranscriptEditor from "@hypr/tiptap/transcript";
45
import { Badge } from "@hypr/ui/components/ui/badge";
56
import { useSessions } from "@hypr/utils/contexts";
67
import { useTranscript } from "./useTranscript";
78

8-
export function Transcript({ sessionId }: { sessionId?: string }) {
9+
export function Transcript({ sessionId, editing }: { sessionId?: string; editing: boolean }) {
910
const currentSessionId = useSessions((s) => s.currentSessionId);
1011
const effectiveSessionId = sessionId || currentSessionId;
1112

@@ -26,7 +27,19 @@ export function Transcript({ sessionId }: { sessionId?: string }) {
2627
}
2728
}, [timeline?.items, isLive, ref]);
2829

29-
const items = timeline?.items || [];
30+
const content = {
31+
type: "doc",
32+
content: [
33+
{
34+
type: "speaker",
35+
attrs: { label: "" },
36+
content: (timeline?.items || []).flatMap((item) => item.text.split(" ")).filter(Boolean).map((word) => ({
37+
type: "word",
38+
content: [{ type: "text", text: word }],
39+
})),
40+
},
41+
],
42+
};
3043

3144
return (
3245
<div
@@ -41,31 +54,14 @@ export function Transcript({ sessionId }: { sessionId?: string }) {
4154
)
4255
: (
4356
<>
44-
{items.length > 0
45-
&& items.map((item, index) => (
46-
<div key={index}>
47-
<p
48-
className={`select-text ${
49-
item.confidence > 0.9
50-
? "font-normal opacity-100"
51-
: item.confidence > 0.8
52-
? "font-normal opacity-80"
53-
: item.confidence > 0.7
54-
? "font-light opacity-60"
55-
: item.confidence > 0.5
56-
? "font-light opacity-70"
57-
: item.confidence > 0.3
58-
? "font-extralight opacity-60"
59-
: item.confidence > 0.1
60-
? "font-extralight opacity-50"
61-
: "font-extralight opacity-40"
62-
}`}
63-
>
64-
{item.text}
65-
</p>
66-
</div>
67-
))}
68-
57+
{(!editing && timeline?.items?.length) && timeline.items.map((item, index) => (
58+
<div key={index}>
59+
<p>
60+
{item.text}
61+
</p>
62+
</div>
63+
))}
64+
{editing && <TranscriptEditor initialContent={content} />}
6965
{isLive && (
7066
<div className="flex items-center gap-2 justify-center py-2 text-neutral-400">
7167
<EarIcon size={14} /> Listening... (there might be a delay)

apps/desktop/src/components/right-panel/views/legacy/ui.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import { type QueryClient, QueryClientProvider } from "@tanstack/react-query";
2-
import { Maximize2Icon } from "lucide-react";
32
import React, { type ReactNode } from "react";
43

5-
import { Button } from "@hypr/ui/components/ui/button";
6-
74
interface WidgetHeaderProps {
85
leading?: ReactNode;
96
title?: ReactNode;
@@ -13,11 +10,7 @@ interface WidgetHeaderProps {
1310
const WidgetHeader = ({
1411
leading,
1512
title,
16-
actions = [
17-
<Button variant="ghost" size="icon" key="maximize">
18-
<Maximize2Icon style={{ width: "16px", height: "16px" }} />
19-
</Button>,
20-
],
13+
actions = [],
2114
}: WidgetHeaderProps) => {
2215
return (
2316
<header style={{ display: "flex", alignItems: "center", gap: "8px" }}>

apps/desktop/src/routes/app.settings.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { zodValidator } from "@tanstack/zod-adapter";
44
import { ArrowLeft } from "lucide-react";
55
import { z } from "zod";
66

7-
import { SettingsHeader, type Tab, TABS } from "@/components/settings/components";
7+
import { MainSidebar, SettingsHeader, type Tab, TABS } from "@/components/settings/components";
88
import { Calendar, Feedback, General, Lab, LocalAI, Notifications, Sound } from "@/components/settings/views";
99
import { Button } from "@hypr/ui/components/ui/button";
1010

@@ -49,6 +49,8 @@ function Component() {
4949
</Button>
5050
)}
5151
</div>
52+
53+
<MainSidebar current={search.tab} onTabClick={handleClickTab} />
5254
</div>
5355

5456
<div className="flex-1 flex h-full w-full flex-col overflow-hidden">

packages/tiptap/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"exports": {
77
"./editor": "./src/editor/index.tsx",
88
"./renderer": "./src/renderer/index.tsx",
9+
"./transcript": "./src/transcript/index.tsx",
910
"./shared": "./src/shared/index.ts"
1011
},
1112
"peerDependencies": {
@@ -15,20 +16,24 @@
1516
"dependencies": {
1617
"@remixicon/react": "^4.6.0",
1718
"@tiptap/core": "^2.12.0",
19+
"@tiptap/extension-document": "^2.12.0",
1820
"@tiptap/extension-highlight": "^2.12.0",
21+
"@tiptap/extension-history": "^2.12.0",
1922
"@tiptap/extension-image": "^2.12.0",
2023
"@tiptap/extension-link": "^2.12.0",
2124
"@tiptap/extension-list-keymap": "^2.12.0",
2225
"@tiptap/extension-placeholder": "^2.12.0",
2326
"@tiptap/extension-strike": "^2.12.0",
2427
"@tiptap/extension-task-item": "^2.12.0",
2528
"@tiptap/extension-task-list": "^2.12.0",
29+
"@tiptap/extension-text": "^2.12.0",
2630
"@tiptap/extension-typography": "^2.12.0",
2731
"@tiptap/extension-underline": "^2.12.0",
2832
"@tiptap/pm": "^2.12.0",
2933
"@tiptap/react": "^2.12.0",
3034
"@tiptap/starter-kit": "^2.12.0",
3135
"clsx": "^2.1.1",
36+
"prosemirror-state": "^1.4.3",
3237
"tippy.js": "^6.3.7",
3338
"turndown": "^7.2.0"
3439
},

packages/tiptap/src/editor/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ const Editor = forwardRef<{ editor: TiptapEditor | null }, EditorProps>(
3838
onUpdate,
3939
shouldRerenderOnTransaction: false,
4040
editorProps: {
41+
attributes: {
42+
class: "tiptap-normal",
43+
},
4144
scrollThreshold: 32,
4245
scrollMargin: 32,
4346
},

packages/tiptap/src/renderer/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ const Renderer = forwardRef<{ editor: TiptapEditor | null }, RendererProps>(
1717
editable: false,
1818
shouldRerenderOnTransaction: false,
1919
editorProps: {
20+
attributes: {
21+
class: "tiptap-normal",
22+
},
2023
scrollThreshold: 32,
2124
scrollMargin: 32,
2225
},

packages/tiptap/src/styles/base.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.tiptap {
1+
.tiptap-normal {
22
word-break: break-word;
33
overflow-wrap: break-word;
44
white-space: pre-wrap;

packages/tiptap/src/styles/nodes/blockquote.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.tiptap {
1+
.tiptap-normal {
22
blockquote {
33
border-left: 3px solid #000000;
44
padding-left: 0.5rem;

0 commit comments

Comments
 (0)