Skip to content

Commit

Permalink
feat: add package @suika/suika-multiplayer
Browse files Browse the repository at this point in the history
  • Loading branch information
F-star committed Aug 18, 2024
1 parent 0301112 commit cd283b4
Show file tree
Hide file tree
Showing 120 changed files with 4,781 additions and 126 deletions.
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
.git
.gitignore
*.md
dist
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"cSpell.words": [
"bbox",
"bboxes",
"bboxs",
"clonedeep",
"Dists",
"Formatjs",
"hocuspocus",
"IRGB",
"IRGBA",
"isequal",
Expand Down
15 changes: 15 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

FROM node:18-alpine AS build
WORKDIR /app

COPY . .

RUN npm config set registry https://registry.npmmirror.com/
RUN npm install -g [email protected]
RUN pnpm install --frozen-lockfile
RUN pnpm build

FROM nginx

COPY --from=build /app/packages/suika-multiplayer/build /usr/share/nginx/html
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
9 changes: 9 additions & 0 deletions nginx/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
server {
listen 8002;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
],
"scripts": {
"dev": "run-p common:dev icons:dev components:dev geo:dev core:dev app:dev",
"dev-m": "run-p common:dev icons:dev components:dev geo:dev core:dev app-m:dev",
"build": "pnpm -r exec pnpm run build",
"app:dev": "pnpm --filter @suika/suika dev",
"app-m:dev": "pnpm --filter @suika/suika-multiplayer dev",
"app:build": "pnpm --filter @suika/suika build",
"storybook": "pnpm --filter @suika/components storybook",
"components:build": "pnpm --filter @suika/components build",
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/components/select/select.scss
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
font-size: 14px;
color: #333;
text-decoration: none;
cursor: pointer;

.sk-select-popover-item-icon {
margin-right: 4px;
Expand All @@ -57,7 +58,6 @@
}
}

cursor: pointer;
&:hover {
color: #fff;
background-color: #0f8fff;
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export class SuikaEditor {
this.keybindingManager.bindEvent();

this.doc = new SuikaDocument({
id: '0-0',
objectName: 'Document',
width: 0,
height: 0,
Expand Down
12 changes: 6 additions & 6 deletions packages/core/src/setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,29 +129,29 @@ export class Setting {
continueClickMaxGap: 350, // millisecond
continueClickDistanceTol: 5,
};
toggle<K extends BooleanKeys<Setting['value']>>(key: K) {
toggle<K extends BooleanKeys<SettingValue>>(key: K) {
const value = this.value[key];
if (typeof value === 'boolean') {
this.set(key, !value);
} else {
console.warn(`toggle ${key} failed, value is not boolean`);
}
}
set<K extends keyof Setting['value']>(key: K, value: Setting['value'][K]) {
set<K extends keyof SettingValue>(key: K, value: SettingValue[K]) {
this.value[key] = value;
this.eventEmitter.emit('update', this.getAttrs());
}
get<K extends keyof Setting['value']>(key: K) {
get<K extends keyof SettingValue>(key: K) {
return this.value[key];
}
getAttrs() {
getAttrs(): SettingValue {
return { ...this.value };
}

on(eventName: 'update', handler: (value: Setting['value']) => void) {
on(eventName: 'update', handler: (value: SettingValue) => void) {
this.eventEmitter.on(eventName, handler);
}
off(eventName: 'update', handler: (value: Setting['value']) => void) {
off(eventName: 'update', handler: (value: SettingValue) => void) {
this.eventEmitter.off(eventName, handler);
}
}
Expand Down
3 changes: 3 additions & 0 deletions packages/suika-multiplayer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@suika/suika-multiplayer

the Web UI of suika editor for multiple user
13 changes: 13 additions & 0 deletions packages/suika-multiplayer/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>suika-multiplayer</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
49 changes: 49 additions & 0 deletions packages/suika-multiplayer/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "@suika/suika-multiplayer",
"version": "0.0.1",
"description": "a graphics editor.",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@floating-ui/react": "^0.22.3",
"@hocuspocus/provider": "^2.13.5",
"@suika/common": "workspace:^",
"@suika/components": "workspace:^",
"@suika/core": "workspace:^",
"@suika/geo": "workspace:^",
"@suika/icons": "workspace:^",
"ahooks": "^3.7.4",
"axios": "^1.7.3",
"classnames": "^2.3.2",
"react": "^18.2.0",
"react-color": "^2.19.3",
"react-dom": "^18.2.0",
"react-intl": "^6.3.2",
"react-scripts": "5.0.1",
"sass": "^1.57.1",
"stats.js": "^0.17.0",
"y-websocket": "^2.0.3",
"yjs": "^13.6.17"
},
"devDependencies": {
"@types/react": "^18.2.25",
"@types/react-color": "^3.0.6",
"@types/react-dom": "^18.2.0",
"@types/stats.js": "^0.17.3",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.55.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5",
"sass": "^1.70.0",
"vite": "^5.0.8",
"vite-plugin-checker": "^0.6.4"
}
}
1 change: 1 addition & 0 deletions packages/suika-multiplayer/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions packages/suika-multiplayer/src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
overscroll-behavior-x: none;
}
42 changes: 42 additions & 0 deletions packages/suika-multiplayer/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import './App.css';

import { useEffect, useState } from 'react';
import { IntlProvider } from 'react-intl';

import Editor from './components/Editor';
import { appEventEmitter } from './events';
import { en, type SupportedLocale, zh } from './locale';

const messageMap = {
zh,
en,
};

const getLocale = (): SupportedLocale => {
const locale = localStorage.getItem('suika-locale') || navigator.language;
return locale.startsWith('zh') ? 'zh' : 'en';
};

function App() {
const [locale, setLocale] = useState(getLocale());

useEffect(() => {
const localeChangeHandler = (locale: SupportedLocale) => {
setLocale(locale);
};
appEventEmitter.on('localeChange', localeChangeHandler);
return () => {
appEventEmitter.off('localeChange', localeChangeHandler);
};
});

return (
<IntlProvider locale={locale} messages={messageMap[locale]}>
<div className="suika">
<Editor />
</div>
</IntlProvider>
);
}

export default App;
21 changes: 21 additions & 0 deletions packages/suika-multiplayer/src/api-service/api-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import axios from 'axios';

const configAxios = () => {
axios.defaults.baseURL = '/api';
axios.interceptors.response.use(
(config) => {
return config;
},
(err) => {
const statusCode = err?.response?.status;
if (statusCode === 401) {
if (location.pathname !== '/login') {
location.href = '/login';
}
}
throw err;
},
);
};

configAxios();
78 changes: 78 additions & 0 deletions packages/suika-multiplayer/src/api-service/api-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import './api-config';

import axios from 'axios';

interface FileItem {
id: number;
title: string;
createdAt: string;
updatedAt: string;
}

type ResStruct<T> = {
code: number;
status: number;
message: string;
error: boolean;
data: T;
};

interface LoginRes {
accessToken: string;
}

interface UserProfileRes {
username: string;
id: number;
}

export const ApiService = {
login: async (username: string, password: string) => {
const res = await axios.post<ResStruct<LoginRes>>('auth/login', {
username,
password,
});
return res.data;
},
register: async (username: string, password: string) => {
const res = await axios.post<ResStruct<LoginRes>>('auth/register', {
username,
password,
});
return res.data;
},
getFileList: async () => {
const res = await axios.get<ResStruct<FileItem[]>>('files');
return res.data;
},
createFile: async (title: string) => {
const res = await axios.post<ResStruct<FileItem[]>>('files/create', {
title,
});
return res.data;
},
getFile: async (id: number) => {
const res = await axios.get<ResStruct<FileItem>>(`files/${id}`);
return res.data;
},
deleteFiles: async (ids: number[]) => {
const res = await axios.delete<ResStruct<FileItem[]>>('files', {
params: {
ids,
},
});
return res.data;
},
updateFile: async (id: number, data: Partial<FileItem>) => {
const res = await axios.patch<ResStruct<FileItem[]>>(`files/${id}`, {
data,
});
return res.data;
},
getUserInfo: async () => {
const res = await axios.get<ResStruct<UserProfileRes>>(
'/users/self/profile',
);
return res.data;
},
};
1 change: 1 addition & 0 deletions packages/suika-multiplayer/src/api-service/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './api-service';
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.suika {
.align-list {
display: flex;
padding: 0 8px;
.align-item {
display: flex;
justify-content: center;
align-items: center;

margin: 0 1px;
border-radius: 3px;
width: 32px;
height: 32px;
color: #333;
&:hover {
background-color: #f2f2f2;
}
}

&.disabled {
pointer-events: none;
opacity: 0.3;
}
}
}
Loading

0 comments on commit cd283b4

Please sign in to comment.