Skip to content

Add profile-stack example #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 62 additions & 97 deletions components/BasicExample/BasicExampleView.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,31 @@
import classNames from 'classnames';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import yorkie from 'yorkie-js-sdk';
import { ProjectCodeType } from './types';
import { Icon } from '../Icons/Icon';
import { Sidebar } from './Sidebar';
import UserContent from './UserContent';

interface DocChangeInfo {
type: 'update' | 'initialize' | 'presence';
content: string;
}

export const UserNames = {
user1: 'User 1',
user2: 'User 2',
user3: 'User 3',
user4: 'User 4',
};
export const UserColors = {
user1: 'green',
user2: 'purple',
user3: 'red',
user4: 'yellow',
};
export const UserColors = ['red', 'yellow', 'green', 'orange', 'blue', 'purple'];

export function BasicExampleView({
rpcAddr,
apiKey,
documentKey,
projectCode,
iframeURL,
documentStructure,
apiKey: apiKey,
codeURL,
userMaxCount = 4,
}: {
rpcAddr: string;
apiKey: string;
documentKey: string;
projectCode: ProjectCodeType;
documentStructure: string;
iframeURL: string;
codeURL: string;
userMaxCount?: number;
}) {
const [docChangeInfos, setDocChangeInfos] = useState<DocChangeInfo[]>([]);
const [userList, setUserList] = useState<('user1' | 'user2' | 'user3' | 'user4')[]>(['user1', 'user2']);
const [userList, setUserList] = useState<number[]>([1, 2]);
const messagesEndRef = useRef<HTMLDivElement>(null);
useEffect(() => {
let unsubscribeDoc: Function;
Expand Down Expand Up @@ -88,102 +71,84 @@ export function BasicExampleView({
useEffect(scrollToBottom, [docChangeInfos, scrollToBottom]);

const deleteUser = useCallback(
(userId: string) => {
(userId: number) => {
if (userList.length === 1) {
alert('You need at least one user');
return;
}
setUserList((prev) => prev.filter((user) => user !== userId));
setUserList((prev) => prev.filter((userNumber) => userNumber !== userId));
},
[setUserList, userList.length],
);

const addUser = useCallback(() => {
if (userList.length === 4) {
if (userList.length === userMaxCount) {
alert("You can't add more users");
return;
}
if (userList[0] !== 'user1') {
setUserList((prev) => ['user1', ...prev]);
if (userList.length === userList[userList.length - 1]) {
setUserList((prev) => [...prev, userList.length + 1]);
return;
}
if (userList[1] !== 'user2') {
setUserList((prev) => prev.slice(0, 1).concat(['user2']).concat(prev.slice(1)));
return;
}
if (userList[2] !== 'user3') {
setUserList((prev) => prev.slice(0, 2).concat(['user3']).concat(prev.slice(2)));
return;
}
if (userList[3] !== 'user4') {
setUserList((prev) => prev.slice(0, 3).concat(['user4']).concat(prev.slice(3)));
return;
for (let i = 0; i < userList.length; i++) {
if (userList[i] !== i + 1) {
setUserList((prev) => [...prev.slice(0, i), i + 1, ...prev.slice(i)]);
return;
}
}
}, [setUserList, userList]);
}, [setUserList, userList, userMaxCount]);

return (
<main className="container">
<Sidebar
title="Kanban Board"
description="Kanban Board is a tool for managing tasks and workflow. It is a visual way to manage tasks and workflow."
codeURL={codeURL}
projectCode={projectCode}
documentStructure={documentStructure}
defaultOpened
/>
<div className="content code_view">
<div className="pin_box">
<ul className="pin_list">
{userList.map((user) => {
return (
<li key={user} className={classNames('pin_item shadow_m')}>
<span className="user" style={{ margin: '0px' }}>
<span className={`icon gradient_180deg_${UserColors[user]}`}></span>
<span className="text">{UserNames[user]}</span>
</span>
<div className="btn_box">
<button
type="button"
className={classNames('btn btn_line btn_pin')}
title="Pin"
onClick={() => {
deleteUser(user);
}}
>
<Icon type="close" />
</button>
</div>
</li>
);
})}
</ul>
<button type="button" className="btn btn_add" onClick={addUser}>
<Icon type="plus" />
</button>
</div>

<ul className="grid_list2">
{userList.map((user) => {
return <UserContent key={user} user={user} iframeURL={iframeURL} />;
<div className="content code_view">
<div className="pin_box">
<ul className="pin_list">
{userList.map((userNumber) => {
return (
<li key={userNumber} className={classNames('pin_item shadow_m')}>
<span className="user">
<span className={`icon gradient_180deg_${UserColors[userNumber % UserColors.length]}`}></span>
<span className="text">{`User ${userNumber}`}</span>
</span>
<div className="btn_box">
<button
type="button"
className={classNames('btn btn_line btn_pin')}
title="Pin"
onClick={() => {
deleteUser(userNumber);
}}
>
<Icon type="close" />
</button>
</div>
</li>
);
})}
</ul>

<div className="log_box">
<div className="log_inner">
<div className="log_title">Event Log</div>
<div style={{ overflowY: 'auto', paddingLeft: 3, maxHeight: 113 - 18 - 5, fontSize: 12 }}>
{docChangeInfos.map((changeInfo, index) => (
<div className="log_desc" key={index}>
<span style={{ fontWeight: 'bold' }}>event</span> -{' '}
{changeInfo.type === 'update' && <span style={{ opacity: 0.5 }}>modification occured at </span>}
<span>{changeInfo.content}</span>
</div>
))}
<div ref={messagesEndRef} />
</div>
<button type="button" className="btn btn_add" onClick={addUser}>
<Icon type="plus" />
</button>
</div>
<ul className="grid_list2">
{userList.map((userNumber) => {
return <UserContent key={userNumber} userNumber={userNumber} iframeURL={iframeURL} />;
})}
</ul>
<div className="log_box">
<div className="log_inner">
<div className="log_title">Event Log</div>
<div style={{ overflowY: 'auto', paddingLeft: 3, maxHeight: 113 - 18 - 5, fontSize: 12 }}>
{docChangeInfos.map((changeInfo, index) => (
<div className="log_desc" key={index}>
<span style={{ fontWeight: 'bold' }}>event</span> -
{changeInfo.type === 'update' && <span style={{ opacity: 0.5 }}>modification occured at </span>}
<span>{changeInfo.content}</span>
</div>
))}
<div ref={messagesEndRef} />
</div>
</div>
</div>
</main>
</div>
);
}
2 changes: 1 addition & 1 deletion components/BasicExample/ProjectCodes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ function ProjectCodes({ code, setProjectCodeState }: Props) {
<div className="codeblock_area">
<em className="file_title">{openedFile.name}</em>
<div className="codeblock_box">
<CodeBlock code={openedFile.content} language="javascript" withLineNumbers />
<CodeBlock code={openedFile.content} language={openedFile.language} withLineNumbers />
</div>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions components/BasicExample/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ export function Sidebar({ defaultOpened = true, title, description, projectCode,
</div>
)}
</div>
<div className="sidebar_bottom" style={{ zIndex: 0 }}>
<div className="sidebar_bottom">
<div className="btn_box">
<a href={codeURL} className="btn gray600 ">
<a href={codeURL} className="btn gray600" target="_blank" rel="noreferrer">
GitHub
</a>
</div>
Expand Down
14 changes: 8 additions & 6 deletions components/BasicExample/UserContent.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React from 'react';
import { UserColors, UserNames } from './BasicExampleView';
import { UserColors } from './BasicExampleView';

function UserContent({ user, iframeURL }: { user: 'user1' | 'user2' | 'user3' | 'user4'; iframeURL: string }) {
function UserContent({ userNumber, iframeURL }: { userNumber: number; iframeURL: string }) {
return (
<li className="grid_item shadow_m" key={user}>
<div className="dashboard" style={{ height: '100%' }}>
<li className="grid_item shadow_m" key={userNumber}>
<div className="dashboard">
<div className="dashboard_top">
<span className={`user gradient_180deg_${UserColors[user]}`}>{UserNames[user]}</span>
<span className={`user gradient_180deg_${UserColors[userNumber % UserColors.length]}`}>
{`User ${userNumber}`}
</span>
</div>
<div className="dashboard_content" style={{ flex: '1 0' }}>
<div className="dashboard_content">
<iframe title="Example" frameBorder="0" src={iframeURL} width="100%" height="100%"></iframe>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions components/BasicExample/index.tsx
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './BasicExampleView';
export * from './types';
export * from './Sidebar';
2 changes: 2 additions & 0 deletions examples/profile-stack/documentStructure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const DocumentStructure = `
`;
Copy link
Member

@hackerwins hackerwins Dec 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that this file is empty because Profile Stack doesn't have a document structure.

How about changing DocumentStructure to How it works and explaining how it behaves?
For that, it might be better to express it in markdown format.

5 changes: 5 additions & 0 deletions examples/profile-stack/files/.env.production.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const language = 'javascript';
export const content = `
VITE_YORKIE_API_ADDR='https://api.yorkie.dev'
VITE_YORKIE_API_KEY='cedaovjuioqlk4pjqn6g'
`;
19 changes: 19 additions & 0 deletions examples/profile-stack/files/index.html.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export const language = 'markup';
export const content = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Profile Stack - Yorkie Example</title>
<link rel="stylesheet" href="/style.css" />
</head>
<body>
<div id="app">
<div id="peerList"></div>
</div>
<script type="module" src="/main.js"></script>
</body>
</html>
`;
17 changes: 17 additions & 0 deletions examples/profile-stack/files/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as styleCss from './style.css';
import * as mainJs from './main.js';
import * as packageJson from './package.json';
import * as indexHtml from './index.html';
import * as utilJs from './util.js';
import * as env from './.env.production.js';

import { Language } from 'prism-react-renderer';

export const files: { [key: string]: { language: Language; content: string } } = {
'style.css': { language: styleCss.language, content: styleCss.content },
'main.js': { language: mainJs.language, content: mainJs.content },
'package.json': { language: packageJson.language, content: packageJson.content },
'index.html': { language: indexHtml.language, content: indexHtml.content },
'util.js': { language: utilJs.language, content: utilJs.content },
'.env.production': { language: env.language, content: env.content },
};
Loading