Eduards commited on
Commit
d41a4ac
·
unverified ·
2 Parent(s): 60cfb5a 0ebd4a6

Merge pull request #422 from SujalXplores/feat/improve-sidebar

Browse files
app/components/sidebar/HistoryItem.tsx CHANGED
@@ -1,5 +1,4 @@
1
  import * as Dialog from '@radix-ui/react-dialog';
2
- import { useEffect, useRef, useState } from 'react';
3
  import { type ChatHistoryItem } from '~/lib/persistence';
4
  import WithTooltip from '~/components/ui/Tooltip';
5
 
@@ -11,78 +10,46 @@ interface HistoryItemProps {
11
  }
12
 
13
  export function HistoryItem({ item, onDelete, onDuplicate, exportChat }: HistoryItemProps) {
14
- const [hovering, setHovering] = useState(false);
15
- const hoverRef = useRef<HTMLDivElement>(null);
16
-
17
- useEffect(() => {
18
- let timeout: NodeJS.Timeout | undefined;
19
-
20
- function mouseEnter() {
21
- setHovering(true);
22
-
23
- if (timeout) {
24
- clearTimeout(timeout);
25
- }
26
- }
27
-
28
- function mouseLeave() {
29
- setHovering(false);
30
- }
31
-
32
- hoverRef.current?.addEventListener('mouseenter', mouseEnter);
33
- hoverRef.current?.addEventListener('mouseleave', mouseLeave);
34
-
35
- return () => {
36
- hoverRef.current?.removeEventListener('mouseenter', mouseEnter);
37
- hoverRef.current?.removeEventListener('mouseleave', mouseLeave);
38
- };
39
- }, []);
40
-
41
  return (
42
- <div
43
- ref={hoverRef}
44
- className="group rounded-md text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary hover:bg-bolt-elements-background-depth-3 overflow-hidden flex justify-between items-center px-2 py-1"
45
- >
46
  <a href={`/chat/${item.urlId}`} className="flex w-full relative truncate block">
47
  {item.description}
48
  <div className="absolute right-0 z-1 top-0 bottom-0 bg-gradient-to-l from-bolt-elements-background-depth-2 group-hover:from-bolt-elements-background-depth-3 box-content pl-3 to-transparent w-10 flex justify-end group-hover:w-15 group-hover:from-99%">
49
- {hovering && (
50
- <div className="flex items-center p-1 text-bolt-elements-textSecondary">
51
- <WithTooltip tooltip="Export chat">
 
 
 
 
 
 
 
 
 
 
 
52
  <button
53
- className="i-ph:download-simple scale-110 mr-2"
 
 
 
 
 
 
 
 
 
 
 
54
  onClick={(event) => {
55
  event.preventDefault();
56
- exportChat(item.id);
57
-
58
- //exportChat(item.messages, item.description);
59
  }}
60
- title="Export chat"
61
  />
62
  </WithTooltip>
63
- {onDuplicate && (
64
- <WithTooltip tooltip="Duplicate chat">
65
- <button
66
- className="i-ph:copy scale-110 mr-2"
67
- onClick={() => onDuplicate?.(item.id)}
68
- title="Duplicate chat"
69
- />
70
- </WithTooltip>
71
- )}
72
- <Dialog.Trigger asChild>
73
- <WithTooltip tooltip="Delete chat">
74
- <button
75
- className="i-ph:trash scale-110"
76
- onClick={(event) => {
77
- // we prevent the default so we don't trigger the anchor above
78
- event.preventDefault();
79
- onDelete?.(event);
80
- }}
81
- />
82
- </WithTooltip>
83
- </Dialog.Trigger>
84
- </div>
85
- )}
86
  </div>
87
  </a>
88
  </div>
 
1
  import * as Dialog from '@radix-ui/react-dialog';
 
2
  import { type ChatHistoryItem } from '~/lib/persistence';
3
  import WithTooltip from '~/components/ui/Tooltip';
4
 
 
10
  }
11
 
12
  export function HistoryItem({ item, onDelete, onDuplicate, exportChat }: HistoryItemProps) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  return (
14
+ <div className="group rounded-md text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary hover:bg-bolt-elements-background-depth-3 overflow-hidden flex justify-between items-center px-2 py-1">
 
 
 
15
  <a href={`/chat/${item.urlId}`} className="flex w-full relative truncate block">
16
  {item.description}
17
  <div className="absolute right-0 z-1 top-0 bottom-0 bg-gradient-to-l from-bolt-elements-background-depth-2 group-hover:from-bolt-elements-background-depth-3 box-content pl-3 to-transparent w-10 flex justify-end group-hover:w-15 group-hover:from-99%">
18
+ <div className="flex items-center p-1 text-bolt-elements-textSecondary opacity-0 group-hover:opacity-100 transition-opacity">
19
+ <WithTooltip tooltip="Export chat">
20
+ <button
21
+ type="button"
22
+ className="i-ph:download-simple scale-110 mr-2 hover:text-bolt-elements-item-contentAccent"
23
+ onClick={(event) => {
24
+ event.preventDefault();
25
+ exportChat(item.id);
26
+ }}
27
+ title="Export chat"
28
+ />
29
+ </WithTooltip>
30
+ {onDuplicate && (
31
+ <WithTooltip tooltip="Duplicate chat">
32
  <button
33
+ type="button"
34
+ className="i-ph:copy scale-110 mr-2 hover:text-bolt-elements-item-contentAccent"
35
+ onClick={() => onDuplicate?.(item.id)}
36
+ title="Duplicate chat"
37
+ />
38
+ </WithTooltip>
39
+ )}
40
+ <Dialog.Trigger asChild>
41
+ <WithTooltip tooltip="Delete chat">
42
+ <button
43
+ type="button"
44
+ className="i-ph:trash scale-110 hover:text-bolt-elements-button-danger-text"
45
  onClick={(event) => {
46
  event.preventDefault();
47
+ onDelete?.(event);
 
 
48
  }}
 
49
  />
50
  </WithTooltip>
51
+ </Dialog.Trigger>
52
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  </div>
54
  </a>
55
  </div>
app/components/sidebar/Menu.client.tsx CHANGED
@@ -129,7 +129,7 @@ export function Menu() {
129
  </a>
130
  </div>
131
  <div className="text-bolt-elements-textPrimary font-medium pl-6 pr-5 my-2">Your Chats</div>
132
- <div className="flex-1 overflow-scroll pl-4 pr-5 pb-5">
133
  {list.length === 0 && <div className="pl-2 text-bolt-elements-textTertiary">No previous conversations</div>}
134
  <DialogRoot open={dialogContent !== null}>
135
  {binDates(list).map(({ category, items }) => (
 
129
  </a>
130
  </div>
131
  <div className="text-bolt-elements-textPrimary font-medium pl-6 pr-5 my-2">Your Chats</div>
132
+ <div className="flex-1 overflow-auto pl-4 pr-5 pb-5">
133
  {list.length === 0 && <div className="pl-2 text-bolt-elements-textTertiary">No previous conversations</div>}
134
  <DialogRoot open={dialogContent !== null}>
135
  {binDates(list).map(({ category, items }) => (
app/components/ui/Tooltip.tsx CHANGED
@@ -1,14 +1,15 @@
1
- import React from 'react';
2
  import * as Tooltip from '@radix-ui/react-tooltip';
3
- import type { ReactNode } from 'react';
4
 
5
- interface ToolTipProps {
6
- tooltip: string;
7
- children: ReactNode | ReactNode[];
8
  sideOffset?: number;
9
  className?: string;
10
  arrowClassName?: string;
11
- tooltipStyle?: any; //TODO better type
 
 
 
12
  }
13
 
14
  const WithTooltip = ({
@@ -18,18 +19,51 @@ const WithTooltip = ({
18
  className = '',
19
  arrowClassName = '',
20
  tooltipStyle = {},
21
- }: ToolTipProps) => {
 
 
 
22
  return (
23
- <Tooltip.Root>
24
  <Tooltip.Trigger asChild>{children}</Tooltip.Trigger>
25
  <Tooltip.Portal>
26
  <Tooltip.Content
27
- className={`bg-bolt-elements-tooltip-background text-bolt-elements-textPrimary px-3 py-2 rounded-lg text-sm shadow-lg ${className}`}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  sideOffset={sideOffset}
29
- style={{ zIndex: 2000, backgroundColor: 'white', ...tooltipStyle }}
 
 
 
30
  >
31
- {tooltip}
32
- <Tooltip.Arrow className={`fill-bolt-elements-tooltip-background ${arrowClassName}`} />
 
 
 
 
 
 
 
33
  </Tooltip.Content>
34
  </Tooltip.Portal>
35
  </Tooltip.Root>
 
 
1
  import * as Tooltip from '@radix-ui/react-tooltip';
 
2
 
3
+ interface TooltipProps {
4
+ tooltip: React.ReactNode;
5
+ children: React.ReactNode;
6
  sideOffset?: number;
7
  className?: string;
8
  arrowClassName?: string;
9
+ tooltipStyle?: React.CSSProperties;
10
+ position?: 'top' | 'bottom' | 'left' | 'right';
11
+ maxWidth?: number;
12
+ delay?: number;
13
  }
14
 
15
  const WithTooltip = ({
 
19
  className = '',
20
  arrowClassName = '',
21
  tooltipStyle = {},
22
+ position = 'top',
23
+ maxWidth = 250,
24
+ delay = 0,
25
+ }: TooltipProps) => {
26
  return (
27
+ <Tooltip.Root delayDuration={delay}>
28
  <Tooltip.Trigger asChild>{children}</Tooltip.Trigger>
29
  <Tooltip.Portal>
30
  <Tooltip.Content
31
+ side={position}
32
+ className={`
33
+ z-[2000]
34
+ px-2.5
35
+ py-1.5
36
+ max-h-[300px]
37
+ select-none
38
+ rounded-md
39
+ bg-bolt-elements-background-depth-3
40
+ text-bolt-elements-textPrimary
41
+ text-sm
42
+ leading-tight
43
+ shadow-lg
44
+ animate-in
45
+ fade-in-0
46
+ zoom-in-95
47
+ data-[state=closed]:animate-out
48
+ data-[state=closed]:fade-out-0
49
+ data-[state=closed]:zoom-out-95
50
+ ${className}
51
+ `}
52
  sideOffset={sideOffset}
53
+ style={{
54
+ maxWidth,
55
+ ...tooltipStyle,
56
+ }}
57
  >
58
+ <div className="break-words">{tooltip}</div>
59
+ <Tooltip.Arrow
60
+ className={`
61
+ fill-bolt-elements-background-depth-3
62
+ ${arrowClassName}
63
+ `}
64
+ width={12}
65
+ height={6}
66
+ />
67
  </Tooltip.Content>
68
  </Tooltip.Portal>
69
  </Tooltip.Root>