Skip to content

Commit dcc6f18

Browse files
Ni-2alsakhaev
andauthored
feat: introduce working with documents and multiple app instances (DAP-4737, DAP-4738, DAP-4739) (#14)
Co-authored-by: Alexander Sakhaev <alsakhaev@gmail.com>
1 parent 8b5f2eb commit dcc6f18

33 files changed

+1442
-171
lines changed

apps/extension/src/contentscript/multitable-panel/assets/vectors.tsx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,52 @@ export const AvailableIcon = () => (
168168
/>
169169
</svg>
170170
)
171+
172+
export const PlusCircle = () => (
173+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
174+
<g transform="translate(-1.5)">
175+
<path
176+
d="M9.50065 14.6663C13.1825 14.6663 16.1673 11.6816 16.1673 7.99967C16.1673 4.31778 13.1825 1.33301 9.50065 1.33301C5.81875 1.33301 2.83398 4.31778 2.83398 7.99967C2.83398 11.6816 5.81875 14.6663 9.50065 14.6663Z"
177+
stroke="#384BFF"
178+
strokeWidth="1.5"
179+
strokeLinecap="round"
180+
strokeLinejoin="round"
181+
/>
182+
<path
183+
d="M9.5 5.33301V10.6663"
184+
stroke="#384BFF"
185+
strokeWidth="1.5"
186+
strokeLinecap="round"
187+
strokeLinejoin="round"
188+
/>
189+
<path
190+
d="M6.83301 8H12.1663"
191+
stroke="#384BFF"
192+
strokeWidth="1.5"
193+
strokeLinecap="round"
194+
strokeLinejoin="round"
195+
/>
196+
</g>
197+
</svg>
198+
)
199+
200+
export const MinusCircle = () => (
201+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
202+
<g transform="translate(-1.5)">
203+
<path
204+
d="M9.50065 14.6663C13.1825 14.6663 16.1673 11.6816 16.1673 7.99967C16.1673 4.31778 13.1825 1.33301 9.50065 1.33301C5.81875 1.33301 2.83398 4.31778 2.83398 7.99967C2.83398 11.6816 5.81875 14.6663 9.50065 14.6663Z"
205+
stroke="#384BFF"
206+
strokeWidth="1.5"
207+
strokeLinecap="round"
208+
strokeLinejoin="round"
209+
/>
210+
<path
211+
d="M6.83301 8H12.1663"
212+
stroke="#384BFF"
213+
strokeWidth="1.5"
214+
strokeLinecap="round"
215+
strokeLinejoin="round"
216+
/>
217+
</g>
218+
</svg>
219+
)

apps/extension/src/contentscript/multitable-panel/components/application-card.tsx

Lines changed: 151 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1-
import { AppMetadata } from '@mweb/engine'
1+
import { AppMetadata, Document, useAppDocuments } from '@mweb/engine'
22
import React from 'react'
33
import styled from 'styled-components'
44
import { Image } from './image'
5+
import { DocumentCard } from './document-card'
6+
import { AppInMutation } from '@mweb/engine/lib/app/services/mutation/mutation.entity'
7+
import { Spin } from 'antd'
58

6-
const Card = styled.div`
9+
const Card = styled.div<{ $backgroundColor?: string }>`
710
position: relative;
811
width: 100%;
912
border-radius: 10px;
10-
background: #fff;
13+
background: ${(p) => p.$backgroundColor};
1114
border: 1px solid #eceef0;
12-
font-family: sans-serif;
15+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
16+
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
1317
&:hover {
1418
background: rgba(24, 121, 206, 0.1);
1519
}
@@ -36,12 +40,20 @@ const CardContent = styled.div`
3640
width: 100%;
3741
`
3842

39-
const TextLink = styled.div<{ bold?: boolean; small?: boolean; ellipsis?: boolean }>`
43+
type TTextLink = {
44+
bold?: boolean
45+
small?: boolean
46+
ellipsis?: boolean
47+
$color?: string
48+
}
49+
50+
const TextLink = styled.div<TTextLink>`
4051
display: block;
4152
margin: 0;
4253
font-size: 14px;
4354
line-height: 18px;
44-
color: ${(p) => (p.bold ? '#11181C !important' : '#687076 !important')};
55+
color: ${(p) =>
56+
p.$color ? `${p.$color} !important` : p.bold ? '#11181C !important' : '#687076 !important'};
4557
font-weight: ${(p) => (p.bold ? '600' : '400')};
4658
font-size: ${(p) => (p.small ? '12px' : '14px')};
4759
overflow: ${(p) => (p.ellipsis ? 'hidden' : 'visible')};
@@ -50,29 +62,13 @@ const TextLink = styled.div<{ bold?: boolean; small?: boolean; ellipsis?: boolea
5062
outline: none;
5163
`
5264

53-
// const Text = styled.p<{ bold?: boolean; small?: boolean; ellipsis?: boolean }>`
54-
// margin: 0;
55-
// font-size: 14px;
56-
// line-height: 20px;
57-
// color: ${(p) => (p.bold ? '#11181C' : '#687076')};
58-
// font-weight: ${(p) => (p.bold ? '600' : '400')};
59-
// font-size: ${(p) => (p.small ? '12px' : '14px')};
60-
// overflow: ${(p) => (p.ellipsis ? 'hidden' : '')};
61-
// text-overflow: ${(p) => (p.ellipsis ? 'ellipsis' : '')};
62-
// white-space: nowrap;
63-
64-
// i {
65-
// margin-right: 3px;
66-
// }
67-
// `
68-
69-
const Thumbnail = styled.div`
65+
const Thumbnail = styled.div<{ $shape: 'circle' | 'default' }>`
7066
display: block;
7167
width: 60px;
7268
height: 60px;
7369
flex-shrink: 0;
7470
border: 1px solid #eceef0;
75-
border-radius: 8px;
71+
border-radius: ${(props) => (props.$shape === 'circle' ? '99em' : '8px')};
7672
overflow: hidden;
7773
outline: none;
7874
transition: border-color 200ms;
@@ -108,6 +104,45 @@ const ButtonLink = styled.button`
108104
}
109105
`
110106

107+
const DocumentsWrapper = styled.div`
108+
display: flex;
109+
padding-bottom: 10px;
110+
`
111+
112+
const SideLine = styled.div`
113+
border: 1px solid #c1c6ce;
114+
margin: 0 10px;
115+
`
116+
117+
const DocumentCardList = styled.div`
118+
width: 100%;
119+
margin-right: 10px;
120+
display: flex;
121+
flex-direction: column;
122+
gap: 6px;
123+
`
124+
125+
const MoreIcon = () => (
126+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
127+
<path
128+
d="M10 8L14 12L10 16"
129+
stroke="#7A818B"
130+
strokeWidth="1.5"
131+
strokeLinecap="round"
132+
strokeLinejoin="round"
133+
/>
134+
<rect
135+
x="3.75"
136+
y="3.75"
137+
width="16.5"
138+
height="16.5"
139+
rx="3.25"
140+
stroke="#7A818B"
141+
strokeWidth="1.5"
142+
/>
143+
</svg>
144+
)
145+
111146
const UncheckedIcon = () => (
112147
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
113148
<rect
@@ -145,27 +180,54 @@ const CheckedIcon = () => (
145180
</svg>
146181
)
147182

148-
export interface Props {
183+
export interface ISimpleApplicationCardProps {
149184
src: string
150185
metadata: AppMetadata['metadata']
186+
disabled: boolean
151187
isChecked: boolean
152188
onChange: (isChecked: boolean) => void
189+
iconShape?: 'circle'
190+
textColor?: string
191+
backgroundColor?: string
192+
}
193+
194+
export interface IApplicationCardWithDocsProps {
195+
src: string
196+
metadata: AppMetadata['metadata']
153197
disabled: boolean
198+
docsIds: AppInMutation['documentId'][]
199+
onDocCheckboxChange: (docId: string | null, isChecked: boolean) => void
200+
onOpenDocumentsModal: (docs: Document[]) => void
201+
}
202+
203+
interface IApplicationCard
204+
extends ISimpleApplicationCardProps,
205+
Omit<IApplicationCardWithDocsProps, 'docsIds'> {
206+
hasDocuments: boolean
207+
usingDocs: (Document | null)[]
208+
allDocs: Document[]
154209
}
155210

156-
export const ApplicationCard: React.FC<Props> = ({
211+
const ApplicationCard: React.FC<IApplicationCard> = ({
157212
src,
158213
metadata,
214+
disabled,
215+
hasDocuments,
216+
iconShape,
217+
textColor,
218+
backgroundColor,
159219
isChecked,
220+
usingDocs,
221+
allDocs,
160222
onChange,
161-
disabled,
223+
onDocCheckboxChange,
224+
onOpenDocumentsModal,
162225
}) => {
163-
const [accountId, , widgetName] = src.split('/')
164-
226+
const [accountId, , appId] = src.split('/')
165227
return (
166-
<Card className={disabled ? 'disabled' : ''}>
228+
<Card $backgroundColor={backgroundColor ?? 'white'} className={disabled ? 'disabled' : ''}>
167229
<CardBody>
168-
<Thumbnail>
230+
<Thumbnail $shape={iconShape ?? 'default'}>
169231
<Image
170232
image={metadata.image}
171233
fallbackUrl="https://ipfs.near.social/ipfs/bafkreifc4burlk35hxom3klq4mysmslfirj7slueenbj7ddwg7pc6ixomu"
@@ -174,22 +236,76 @@ export const ApplicationCard: React.FC<Props> = ({
174236
</Thumbnail>
175237

176238
<CardContent>
177-
<TextLink bold ellipsis>
178-
{metadata.name || widgetName}
239+
<TextLink $color={textColor} bold ellipsis>
240+
{metadata.name || appId}
179241
</TextLink>
180242

181243
<TextLink small ellipsis>
182244
@{accountId}
183245
</TextLink>
184246
</CardContent>
247+
185248
<ButtonLink
186249
className={disabled ? 'disabled' : ''}
187250
disabled={disabled}
188-
onClick={() => onChange(!isChecked)}
251+
onClick={hasDocuments ? () => onOpenDocumentsModal(allDocs) : () => onChange(!isChecked)}
189252
>
190-
{isChecked ? <CheckedIcon /> : <UncheckedIcon />}
253+
{hasDocuments ? <MoreIcon /> : isChecked ? <CheckedIcon /> : <UncheckedIcon />}
191254
</ButtonLink>
192255
</CardBody>
256+
257+
{hasDocuments && usingDocs.length ? (
258+
<DocumentsWrapper>
259+
<SideLine />
260+
<DocumentCardList>
261+
{usingDocs.map((doc) => (
262+
<DocumentCard
263+
key={doc?.id || 'empty'}
264+
src={doc?.id ?? null}
265+
metadata={doc?.metadata ?? null}
266+
onChange={() => onDocCheckboxChange(doc?.id ?? null, false)}
267+
disabled={disabled}
268+
appMetadata={metadata}
269+
/>
270+
))}
271+
</DocumentCardList>
272+
</DocumentsWrapper>
273+
) : null}
193274
</Card>
194275
)
195276
}
277+
278+
export const SimpleApplicationCard: React.FC<ISimpleApplicationCardProps> = (props) => (
279+
<ApplicationCard
280+
{...props}
281+
hasDocuments={false}
282+
onOpenDocumentsModal={() => null}
283+
onDocCheckboxChange={() => null}
284+
usingDocs={[]}
285+
allDocs={[]}
286+
/>
287+
)
288+
289+
export const ApplicationCardWithDocs: React.FC<IApplicationCardWithDocsProps> = (props) => {
290+
const { src, docsIds } = props
291+
const { documents, isLoading } = useAppDocuments(src)
292+
const usingDocs: (Document | null)[] = documents?.filter((doc) => docsIds.includes(doc.id))
293+
if (docsIds.includes(null)) usingDocs.unshift(null)
294+
295+
return isLoading ? (
296+
<Card>
297+
<CardBody>
298+
<Spin style={{ width: '100%' }} />
299+
</CardBody>
300+
</Card>
301+
) : (
302+
<ApplicationCard
303+
{...props}
304+
hasDocuments={true}
305+
isChecked={false}
306+
onChange={() => null}
307+
usingDocs={usingDocs}
308+
allDocs={documents}
309+
/>
310+
)
311+
}

apps/extension/src/contentscript/multitable-panel/components/button.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import styled from 'styled-components'
22

3-
export const Button = styled.button`
3+
export const Button = styled.button<{ primary?: boolean }>`
44
display: flex;
55
justify-content: center;
66
align-items: center;
7-
border: 1px solid rgba(226, 226, 229, 1);
8-
color: rgba(2, 25, 58, 1);
7+
border: ${(p) => (p.primary ? 'none' : '1px solid rgba(226, 226, 229, 1)')};
8+
color: ${(p) => (p.primary ? '#fff' : 'rgba(2, 25, 58, 1)')};
9+
background: ${(p) => (p.primary ? 'rgba(56, 75, 255, 1)' : 'inherit')};
910
width: 175px;
1011
height: 42px;
1112
border-radius: 10px;

0 commit comments

Comments
 (0)