Skip to content

Commit 1d26f35

Browse files
authored
Snippets Scrolling, Recents in Extension (#280)
#280 * Snippet screen lock params added * Snippet copy on icon click, public node on sidebar fixes * Extension Toggle sidebar position fixes * Use MexIcon component instead of iconfiy icon component * Snippets delete whole page re-rendering issue fixed * Recents, static header, show auto scroll * added changeset
1 parent caafbb5 commit 1d26f35

32 files changed

+276
-117
lines changed

.changeset/friendly-cobras-care.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'mexit': patch
3+
'mexit-webapp': patch
4+
---
5+
6+
Right Sidebar UX fixes

apps/extension/src/Components/Editor/SnippetPreview.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export interface SnippetPreviewProps {
3333
hover?: boolean
3434
// editable?: boolean
3535
label?: string
36+
disableClick?: boolean
3637
allowClosePreview?: boolean
3738
icon?: string
3839
iconTooltip?: string
@@ -46,6 +47,7 @@ const SnippetPreview = ({
4647
hover,
4748
label,
4849
placement,
50+
disableClick,
4951
// editable = true,
5052
setPreview,
5153
icon,
@@ -83,8 +85,10 @@ const SnippetPreview = ({
8385
return (
8486
<NestedFloating
8587
hover={hover}
88+
disableClick={disableClick}
8689
root={getElementById('ext-side-nav')}
8790
label={label}
91+
scrollLock={false}
8892
placement={placement}
8993
persist={!allowClosePreview}
9094
open={preview}

apps/extension/src/Components/EditorPreviewRenderer.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ const PreviewStyles = styled(EditorStyles)<{ noMouseEvents: boolean }>`
2828
/* user-select: none; */
2929
font-size: 0.9rem;
3030
31-
${TodoContainer}, button, input, textarea, select, option {
31+
${TodoContainer}, button,
32+
input,
33+
textarea,
34+
select,
35+
option {
3236
pointer-events: none;
3337
}
3438
`

apps/extension/src/Components/Renderers/Screenshot/Screenshot.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,8 @@ const Screenshot = () => {
337337
]
338338
appendAndSave({ nodeid, content: appendContent, saveAndExit: true, notification: true })
339339
resetSpotlitState()
340+
} else {
341+
mog('Base 64 string not found')
340342
}
341343
} catch (error) {
342344
mog('SSCaptureError', { error })

apps/extension/src/Components/Sidebar/ContextInfoBar.tsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useMemo } from 'react'
22

3-
import { SnippetCards, CenteredFlex } from '@mexit/shared'
3+
import { SnippetCards, CenteredFlex, List } from '@mexit/shared'
44

55
import { useHighlightStore } from '../../Stores/useHighlightStore'
66
import { GenericCard } from './GenericCard'
@@ -67,7 +67,7 @@ export function ContextInfoBar() {
6767
// }, [search])
6868

6969
return (
70-
<SnippetCards>
70+
<SnippetCards fullHeight={false}>
7171
<ShortenerComponent />
7272
{/* <SidebarListFilterWrapper>
7373
<SidebarListFilter>
@@ -82,14 +82,16 @@ export function ContextInfoBar() {
8282
<Infobox root={getElementById('ext-side-nav')} text={HighlightSidebarHelp} />
8383
</SidebarListFilterWrapper> */}
8484
{pageHighlights ? (
85-
<HighlightGroups highlights={pageHighlights} />
85+
<List scrollable>
86+
<HighlightGroups highlights={pageHighlights} />
87+
</List>
8688
) : (
8789
<div>
8890
<CenteredFlex>
8991
<h2>Hi there</h2>
9092
<p>Let's get you started</p>
9193
</CenteredFlex>
92-
<SnippetCards>
94+
<SnippetCards fullHeight={false}>
9395
{basicOnboarding.map((item) => (
9496
<GenericCard icon={item.icon} title={item.title} description={item.description} />
9597
))}

apps/extension/src/Components/Sidebar/DraggableToggle.tsx

+11-6
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ import styled, { css } from 'styled-components'
77

88
import { TitleWithShortcut } from '@workduck-io/mex-components'
99

10-
import { mog } from '@mexit/core'
11-
import { MexIcon, WDLogo } from '@mexit/shared'
10+
import { WDLogo } from '@mexit/shared'
1211

1312
import { useSidebarTransition } from '../../Hooks/useSidebarTransition'
1413
import { useLayoutStore } from '../../Stores/useLayoutStore'
@@ -22,16 +21,16 @@ const DragIcon = styled(Icon)<{ $show: boolean }>`
2221
`}
2322
`
2423

25-
const ToggleWrapper = styled.div<{ $expanded?: boolean; $top: number }>`
24+
const ToggleWrapper = styled.div<{ $endColumnWidth?: string; $expanded?: boolean; $top: number }>`
2625
position: fixed;
2726
display: flex;
2827
align-items: center;
2928
30-
${({ $expanded, $top, theme }) =>
29+
${({ $expanded, $top, $endColumnWidth, theme }) =>
3130
$expanded
3231
? css`
3332
top: ${$top}px;
34-
right: 405px;
33+
right: calc(${($endColumnWidth ?? '400px') + ' + ' + (theme.additional.hasBlocks ? 0 : -15)}px);
3534
`
3635
: css`
3736
top: ${$top}px;
@@ -130,7 +129,13 @@ export const DraggableToggle = () => {
130129
appendTo={() => getElementById('ext-side-nav')}
131130
content={<TitleWithShortcut title={rhSidebar.expanded ? 'Collapse Sidebar' : 'Expand Sidebar'} />}
132131
>
133-
<ToggleWrapper ref={intentRef as any} $top={toggleTop} $expanded={rhSidebar.expanded} onClick={toggleRHSidebar}>
132+
<ToggleWrapper
133+
$endColumnWidth={endColumnWidth}
134+
ref={intentRef as any}
135+
$top={toggleTop}
136+
$expanded={rhSidebar.expanded}
137+
onClick={toggleRHSidebar}
138+
>
134139
<WDLogo />
135140

136141
<DragIcon ref={handleRef} $show={isHovering} icon="ic:outline-drag-indicator" />

apps/extension/src/Components/Sidebar/NodeCard.tsx

+21-10
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
11
import React, { useMemo } from 'react'
22

3-
import { Icon } from '@iconify/react'
4-
import toast from 'react-hot-toast'
53
import styled from 'styled-components'
64

75
import { convertContentToRawText, MEXIT_FRONTEND_URL_BASE, mog, WORKSPACE_HEADER } from '@mexit/core'
86
import {
9-
CenteredFlex,
107
CopyButton,
118
GenericFlex,
9+
IconButton,
10+
MexIcon,
1211
SnippetCardFooter,
13-
SnippetCardHeader,
1412
SnippetCardWrapper,
15-
SnippetContentPreview,
16-
TagsLabel
13+
SnippetContentPreview
1714
} from '@mexit/shared'
1815

1916
import { useAuthStore } from '../../Hooks/useAuth'
2017
import { getTitleFromPath } from '../../Hooks/useLinks'
2118
import { useNodes } from '../../Hooks/useNodes'
2219
import { useContentStore } from '../../Stores/useContentStore'
2320
import useDataStore from '../../Stores/useDataStore'
21+
import { useRecentsStore } from '../../Stores/useRecentsStore'
2422

2523
export const NodeCardHeader = styled.div<{ $noHover?: boolean }>`
2624
display: flex;
@@ -36,6 +34,7 @@ export const NodeCard = ({ nodeId }: { nodeId: string }) => {
3634
const { publicNodes, setNodePrivate, setNodePublic, checkNodePublic } = useDataStore()
3735
const { getNode } = useNodes()
3836
const getContent = useContentStore((store) => store.getContent)
37+
const addInRecents = useRecentsStore((s) => s.addRecent)
3938
const getWorkspaceId = useAuthStore((store) => store.getWorkspaceId)
4039

4140
const isNodePublic = useMemo(() => {
@@ -66,6 +65,7 @@ export const NodeCard = ({ nodeId }: { nodeId: string }) => {
6665
if (error) {
6766
mog('ErrorMakingNodePrivate', error)
6867
} else {
68+
addInRecents(nodeId)
6969
setNodePrivate(nodeId)
7070
}
7171
})
@@ -84,29 +84,40 @@ export const NodeCard = ({ nodeId }: { nodeId: string }) => {
8484
if (error) {
8585
mog('ErrorMakingNodePublic', error)
8686
} else {
87+
addInRecents(nodeId)
8788
setNodePublic(nodeId)
8889
}
8990
})
9091
}
9192
}
9293

94+
const onNotePublic = (event) => {
95+
event.stopPropagation()
96+
flipPublicAccess()
97+
}
98+
9399
return (
94100
<SnippetCardWrapper>
95101
<NodeCardHeader $noHover>
96102
<GenericFlex>
97-
<Icon icon="gg:file-document" />
103+
<MexIcon $noHover icon="gg:file-document" />
98104
{getTitleFromPath(node?.path)}
99105
</GenericFlex>
100106
<GenericFlex>
101107
{isNodePublic ? (
102-
<Icon icon="bi:cloud" onClick={() => flipPublicAccess()} />
108+
<IconButton
109+
title="Make Note Public"
110+
size="16px"
111+
icon="material-symbols:public-off-rounded"
112+
onClick={onNotePublic}
113+
/>
103114
) : (
104-
<Icon icon="bi:cloud-slash" onClick={() => flipPublicAccess()} />
115+
<IconButton title="Make Note Private" size="16px" icon="material-symbols:public" onClick={onNotePublic} />
105116
)}
106117
{isNodePublic && (
107118
<CopyButton
108119
text={`${MEXIT_FRONTEND_URL_BASE}/share/${nodeId}`}
109-
size="20px"
120+
size="16px"
110121
beforeCopyTooltip="Copy link"
111122
afterCopyTooltip="Link copied!"
112123
/>
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,37 @@
11
import React, { useEffect, useRef, useState } from 'react'
22

33
import searchLine from '@iconify/icons-ri/search-line'
4-
import { Icon } from '@iconify/react'
54
import { debounce } from 'lodash'
5+
import { useTheme } from 'styled-components'
66

7-
import { mog } from '@mexit/core'
8-
import { SidebarListFilterWrapper, SidebarListFilter, Input, SnippetCards } from '@mexit/shared'
7+
import { Infobox } from '@workduck-io/mex-components'
98

9+
import { BASE_TASKS_PATH, isParent, mog } from '@mexit/core'
10+
import {
11+
SidebarListFilterWrapper,
12+
SidebarListFilter,
13+
Input,
14+
SnippetCards,
15+
MexIcon,
16+
NotesInfoBarHelp,
17+
List,
18+
CenteredColumn
19+
} from '@mexit/shared'
20+
21+
import { useLinks } from '../../Hooks/useLinks'
1022
import useRaju from '../../Hooks/useRaju'
11-
import useDataStore from '../../Stores/useDataStore'
23+
import { useRecentsStore } from '../../Stores/useRecentsStore'
24+
import { getElementById } from '../../contentScript'
1225
import { NodeCard } from './NodeCard'
1326

1427
export const NotesInfoBar = () => {
15-
const publicNodes = useDataStore((state) => state.publicNodes)
1628
const [search, setSearch] = useState('')
1729
const [searchedNodes, setSearchedNodes] = useState<string[]>()
1830
const { dispatch } = useRaju()
31+
const recentNotes = useRecentsStore((s) => s.lastOpened)
32+
33+
const theme = useTheme()
34+
const { getILinkFromNodeid } = useLinks()
1935

2036
const inputRef = useRef<HTMLInputElement>(null)
2137

@@ -24,35 +40,69 @@ export const NotesInfoBar = () => {
2440
}
2541

2642
const onSearch = async (newSearchTerm: string) => {
27-
const res = await dispatch('SEARCH', ['node'], newSearchTerm)
43+
try {
44+
const res = await dispatch('SEARCH', ['node'], newSearchTerm)
45+
const results = res?.map((item) => item.id) ?? []
46+
setSearchedNodes(results)
47+
} catch (err) {
48+
mog('[NOTE SEARCH]: Unable to search', { err })
49+
}
50+
}
51+
52+
const getRecentList = (noteIds: Array<string>, limit = 5) => {
53+
const recentList = []
54+
55+
noteIds?.forEach((noteId) => {
56+
const noteLink = getILinkFromNodeid(noteId, true)
57+
58+
if (noteLink && !isParent(noteLink.path, BASE_TASKS_PATH)) {
59+
recentList.push(noteId)
60+
}
61+
})
62+
63+
if (recentList.length > limit) {
64+
return recentList.reverse().slice(0, limit)
65+
}
2866

29-
setSearchedNodes(res?.map((item) => item.id))
67+
return recentList?.reverse()
3068
}
3169

3270
useEffect(() => {
3371
if (search !== '') {
3472
onSearch(search)
3573
} else {
36-
setSearchedNodes(publicNodes)
74+
const defaultList = getRecentList(recentNotes)
75+
setSearchedNodes(defaultList)
3776
}
38-
}, [search])
77+
}, [search, recentNotes])
3978

4079
return (
4180
<SnippetCards>
4281
<SidebarListFilterWrapper>
43-
<SidebarListFilter>
44-
<Icon icon={searchLine} />
82+
<SidebarListFilter noMargin>
83+
<MexIcon $noHover height={20} width={20} icon={searchLine} margin="0.6rem 0" />
4584
<Input
4685
autoFocus
86+
fontSize="1rem"
4787
placeholder={'Search notes'}
4888
onChange={debounce((e) => onSearchChange(e), 250)}
4989
ref={inputRef}
5090
/>
5191
</SidebarListFilter>
92+
<Infobox text={NotesInfoBarHelp} root={getElementById('ext-side-nav')} />
5293
</SidebarListFilterWrapper>
53-
{searchedNodes?.map((nodeId) => (
54-
<NodeCard key={nodeId} nodeId={nodeId} />
55-
))}
94+
{!search && !searchedNodes?.length ? (
95+
<CenteredColumn>
96+
<MexIcon color={theme.colors.primary} $noHover width="32" height="32" icon="gg:file-document" />
97+
<p>All your recents will shown here!</p>
98+
</CenteredColumn>
99+
) : (
100+
<List scrollable>
101+
{searchedNodes?.map((nodeId) => (
102+
<NodeCard key={nodeId} nodeId={nodeId} />
103+
))}
104+
</List>
105+
)}
56106
</SnippetCards>
57107
)
58108
}

0 commit comments

Comments
 (0)