Skip to content

Commit fb49bc7

Browse files
authored
Merge pull request #35 from dyte-in/staging
chore: release
2 parents b664fd9 + f542e84 commit fb49bc7

File tree

17 files changed

+1213
-144
lines changed

17 files changed

+1213
-144
lines changed

package-lock.json

Lines changed: 317 additions & 34 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,30 @@
55
"main": "index.js",
66
"scripts": {
77
"dev": "vite",
8+
"preview": "vite preview",
89
"build": "tsc && vite build",
910
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
10-
"preview": "vite preview"
11+
"publish": "npm run build && cp dyte-config.json ./dist/dyte-config.json && cd dist && dyte plugins publish -l",
12+
"publish-devel": "npm run build && cp dyte-config-staging.json ./dist/dyte-config.json && cd dist && dyte plugins publish -l"
1113
},
1214
"keywords": [],
1315
"author": "",
1416
"license": "ISC",
1517
"dependencies": {
16-
"@dytesdk/plugin-sdk": "^2.2.0",
17-
"@tldraw/tldraw": "^1.29.2",
18+
"@dytesdk/plugin-sdk": "2.4.0",
19+
"@tldraw/tldraw": "^1.20.0",
1820
"axios": "^1.4.0",
1921
"core-js": "^3.30.2",
22+
"jspdf": "^2.5.1",
2023
"react": "^18.2.0",
2124
"react-app-polyfill": "^3.0.0",
22-
"react-dom": "^18.2.0"
25+
"react-dom": "^18.2.0",
26+
"uuid": "^9.0.1"
2327
},
2428
"devDependencies": {
2529
"@types/react": "^18.0.37",
2630
"@types/react-dom": "^18.0.11",
31+
"@types/uuid": "^9.0.8",
2732
"@typescript-eslint/eslint-plugin": "^5.59.0",
2833
"@typescript-eslint/parser": "^5.59.0",
2934
"@vitejs/plugin-react": "^4.0.0",

src/App.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import './index.css';
2-
import { useContext } from 'react';
2+
import { useContext, useEffect } from 'react';
33
import { MainContext } from './context';
44
import logo from '../src/assets/icon.png';
5+
import logoWhite from '../src/assets/logo-white.png';
56
import Canvas from './pages/canvas/Canvas';
67

78
const App = () => {
8-
const { plugin, meetingId, self } = useContext(MainContext);
9+
const { plugin, meetingId, self, config } = useContext(MainContext);
910

1011
return (
1112
<div className='container'>
@@ -14,7 +15,15 @@ const App = () => {
1415
? (
1516
<Canvas />
1617
)
17-
: <div className="loading-page"><img src={logo} /> <p>Whiteboard</p></div>
18+
: (
19+
config?.darkMode
20+
? <div className='loading-page-dark'>
21+
<img src={logoWhite} /> <p>Whiteboard</p>
22+
</div>
23+
: <div className="loading-page">
24+
<img src={logo} /> <p>Whiteboard</p>
25+
</div>
26+
)
1827
}
1928
</div>
2029
)

src/api/summary.tsx

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import React, { useEffect } from 'react'
2+
import { TDExportType, TldrawApp } from '@tldraw/tldraw'
3+
import DytePlugin from '@dytesdk/plugin-sdk'
4+
5+
6+
interface Props {
7+
app: TldrawApp | undefined,
8+
plugin: DytePlugin | undefined,
9+
pageHistory: Set<string>,
10+
setLoading: React.Dispatch<React.SetStateAction<boolean>>;
11+
}
12+
13+
const blobToBase64 = (blob: Blob): Promise<string> => {
14+
const reader = new FileReader();
15+
reader.readAsDataURL(blob);
16+
return new Promise(resolve => {
17+
reader.onloadend = () => {
18+
resolve(reader.result as string);
19+
};
20+
});
21+
};
22+
23+
const summary = ({ app, plugin, pageHistory, setLoading }: Props) => {
24+
useEffect(() => {
25+
if (!app || !plugin) return;
26+
27+
plugin.room.on('get-summary', async () => {
28+
let image: string | undefined;
29+
try {
30+
const preview = await app.getImage(TDExportType.JPG, {
31+
transparentBackground: true,
32+
});
33+
if (preview) {
34+
image = await blobToBase64(preview)
35+
}
36+
} catch (e) {}
37+
38+
plugin.room.emitEvent('board-summary', {
39+
document: app.document,
40+
pageIds: pageHistory,
41+
preview: image,
42+
});
43+
})
44+
45+
plugin.room.on('load-app', ({payload}) => {
46+
const document = payload.document;
47+
setLoading(true);
48+
(app as TldrawApp).updateDocument(document);
49+
plugin.emit('load-app-remote', { document });
50+
setLoading(false);
51+
})
52+
53+
plugin.on('load-app-remote', ({ document }) => {
54+
setLoading(true);
55+
(app as TldrawApp).updateDocument(document);
56+
setLoading(false);
57+
})
58+
59+
plugin.room.on('set-page', ({ payload }) => {
60+
const page = payload.pageId;
61+
(app as TldrawApp).changePage(page);
62+
})
63+
64+
plugin.room.on('add-page', ({ payload }) => {
65+
const pageName = payload.page;
66+
(app as TldrawApp).createPage(undefined, pageName);
67+
})
68+
}, [app, plugin])
69+
}
70+
71+
export default summary

src/assets/logo-white.png

4.93 KB
Loading
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import { useContext, useEffect, useState } from 'react'
2+
import './pagination.css'
3+
import Icon from '../icon/Icon'
4+
import { MainContext } from '../../context';
5+
import { TldrawApp } from '@tldraw/tldraw';
6+
import { INDEX, setIndex, storeConf } from '../../utils/constants';
7+
import { v4 } from 'uuid';
8+
9+
const index = () => {
10+
const [showDropdown, setShowDropdown] = useState<boolean>(false);
11+
const { activeTool, config, pages, setPages, page, setPage, loading, plugin, app, following } = useContext(MainContext);
12+
13+
const addPage = async () => {
14+
setIndex(INDEX + 1);
15+
const pageObject = {
16+
name: `Page ${INDEX}`,
17+
id: v4(),
18+
};
19+
20+
// create new page to dyte stores
21+
const PageStore = plugin.stores.get('page');
22+
await PageStore.bulkSet([
23+
{ key: 'currentPage', payload: pageObject },
24+
{ key: pageObject.id, payload: pageObject.name },
25+
])
26+
27+
// create new page state
28+
setPages((p: any) => [...p, pageObject]);
29+
setPage(pageObject);
30+
31+
// create new page in tldraw
32+
(app as TldrawApp).createPage(pageObject.id, pageObject.name);
33+
setShowDropdown((d) => !d);
34+
}
35+
const deletePage = (id: string) => {
36+
// delete page from tldraw
37+
app.deletePage(id);
38+
const pageId = app.appState.currentPageId;
39+
const { name } = (app as TldrawApp).document.pages[pageId];
40+
41+
// update page state
42+
setPages((p: any) => p.filter((x: any) => x.id !== id));
43+
setPage({ name, id: pageId });
44+
45+
// delete page from dyte stores
46+
const PageStore = plugin.stores.get('page');
47+
PageStore.bulkDelete([{key: id}]);
48+
PageStore.set('currentPage', { name, id: pageId });
49+
setShowDropdown((d) => !d);
50+
}
51+
const switchPage = (pageObject: { name: string; id: string }) => {
52+
// change page state
53+
setPage(pageObject);
54+
// change tldraw page
55+
app.changePage(pageObject.id);
56+
// change dyte store page
57+
const PageStore = plugin.stores.get('page');
58+
PageStore.set('currentPage', pageObject)
59+
}
60+
61+
// update pages when store changes come
62+
useEffect(() => {
63+
if (!plugin || !app) return;
64+
65+
const PageStore = plugin.stores.create('page', storeConf);
66+
PageStore.subscribe('*', (data: any) => {
67+
const pId = Object.keys(data)[0];
68+
if (!data[pId]) {
69+
setPages((p: any) => p.filter((x: any) => x.id !== pId));
70+
app.deletePage(pId);
71+
}
72+
const currentPage = data.currentPage;
73+
if (!currentPage) return;
74+
if (!loading) {
75+
const p = app.getPage(currentPage.id);
76+
if (!p) {
77+
setPages((p: any) => [...p, currentPage]);
78+
app.createPage(currentPage.id, currentPage.name);
79+
setIndex(INDEX + 1);
80+
} else {
81+
app.changePage(currentPage.id);
82+
}
83+
}
84+
setPage(currentPage);
85+
})
86+
return () => {
87+
PageStore.unsubscribe('*');
88+
}
89+
}, [loading, app, plugin])
90+
91+
// closes pagination when following someone
92+
useEffect(() => {
93+
if (following?.length) {
94+
setShowDropdown(false);
95+
}
96+
}, [following])
97+
98+
// closes pagination while drawing (IMP so that user does not end up creating a page while drawing)
99+
useEffect(() => {
100+
if (activeTool !== 'select') {
101+
setShowDropdown(false);
102+
}
103+
}, [activeTool])
104+
105+
return (
106+
<div className={ config?.darkMode ? "pagination-dark" : "pagination"}>
107+
<div className="pagination-header" onClick={() => {
108+
setShowDropdown((s) => !s);
109+
}}>
110+
<div>{page?.name}</div>
111+
<Icon
112+
icon={showDropdown ? 'less' : 'more'} className="pagination-icon"
113+
/>
114+
</div>
115+
{
116+
showDropdown && (
117+
<div className={config?.darkMode ? "pagination-dropdown-dark" : "pagination-dropdown"}>
118+
{
119+
pages.map((p: any) => (
120+
<div
121+
key={p.id}
122+
className="pagination-element"
123+
>
124+
<div className="page-label" onClick={() => switchPage(p)} >{p.name}</div>
125+
{pages.length > 1 && (
126+
<Icon
127+
icon="delete"
128+
onClick={() => deletePage(p.id)}
129+
className="pagination-icon"
130+
/>
131+
)}
132+
</div>
133+
))
134+
}
135+
<div className={config?.darkMode ? "pagination-create-dark" : "pagination-create"} onClick={addPage}>
136+
Create Page
137+
<Icon icon="add" className="pagination-icon" />
138+
</div>
139+
</div>
140+
)
141+
}
142+
</div>
143+
)
144+
}
145+
146+
export default index
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
.pagination {
2+
@apply flex flex-col cursor-pointer;
3+
}
4+
.pagination-dark {
5+
@apply flex flex-col cursor-pointer text-white;
6+
}
7+
.pagination-header {
8+
@apply flex flex-row items-center;
9+
}
10+
.pagination-icon {
11+
@apply h-6 w-6;
12+
}
13+
.pagination-dropdown {
14+
@apply absolute left-0 top-11 bg-[#f8f8f8] rounded-md shadow-[0_8px_30px_rgb(0,0,0,0.12)];
15+
max-height: 80vh;
16+
overflow-y: auto;
17+
min-width: 130px;
18+
}
19+
.pagination-dropdown-dark {
20+
@apply absolute left-0 top-11 rounded-md shadow-[0_8px_30px_rgb(0,0,0,0.12)] text-white bg-[#353D43];
21+
max-height: 80vh;
22+
overflow-y: auto;
23+
min-width: 130px;
24+
}
25+
.pagination-element {
26+
@apply flex flex-row items-center justify-between px-2 h-10;
27+
}
28+
.pagination-create {
29+
@apply flex flex-row items-center justify-between p-1 border-solid border-gray-300 border-0 border-t-[1px] h-10;
30+
}
31+
.pagination-create-dark {
32+
@apply flex flex-row items-center justify-between p-1 border-solid border-gray-600 border-0 border-t-[1px] h-10;
33+
}
34+
.page-label {
35+
@apply flex-grow;
36+
}

src/components/presence/Presence.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const Presence = () => {
3737
const n = name.split(' ');
3838
let initials = '';
3939
n.map((x, index) => {
40-
if (index < 2) initials += x[0].toUpperCase();
40+
if (index < 2) initials += x[0]?.toUpperCase();
4141
})
4242
return initials ?? 'P';
4343
}
@@ -89,6 +89,15 @@ const Presence = () => {
8989
}
9090
}, [followers]);
9191

92+
/**
93+
* Do not show presence icons if you are following someone.
94+
* Do not show presence icons if you are followed by everyone
95+
*/
96+
if (
97+
following[0]
98+
|| followers?.size === Object.keys(users)?.length
99+
) return null;
100+
92101
return (
93102
<div>
94103
{(() => {

0 commit comments

Comments
 (0)