-
-
-
-
{htmlCode}
-
+
+
+
+ {activeTab === 'preview' && (
+
+ )}
+ {activeTab === 'html' && (
+
{htmlCode}
+ )}
+ {activeTab === 'css' &&
css 파싱 기능은 구현 중 입니다.
}
+
+
-
+
+
+
);
};
diff --git a/apps/client/src/widgets/workspace/customCategory.ts b/apps/client/src/widgets/workspace/customCategory.ts
new file mode 100644
index 00000000..2242a722
--- /dev/null
+++ b/apps/client/src/widgets/workspace/customCategory.ts
@@ -0,0 +1,43 @@
+import * as Blockly from 'blockly/core';
+import { CategoryInfo } from 'blockly/core/utils/toolbox';
+import { IToolbox } from 'blockly';
+import { CATEGORY_ICONS } from '@/shared/utils';
+
+export default class CustomCategory extends Blockly.ToolboxCategory {
+ constructor(
+ categoryDef: CategoryInfo,
+ toolbox: IToolbox,
+ optParent: Blockly.ICollapsibleToolboxItem
+ ) {
+ super(categoryDef, toolbox, optParent);
+ }
+
+ addColourBorder_(colour: string) {
+ this.rowDiv_!.style.color = colour;
+ }
+
+ setSelected(isSelected: boolean) {
+ if (isSelected) {
+ this.rowDiv_!.style.backgroundColor = this.colour_;
+ this.rowDiv_!.style.color = 'white';
+ } else {
+ this.rowDiv_!.style.backgroundColor = 'white';
+ this.rowDiv_!.style.color = this.colour_;
+ }
+ }
+
+ createIconDom_() {
+ const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+
+ svg.setAttribute('width', '24');
+ svg.setAttribute('height', '24');
+ svg.setAttribute('viewBox', '0 0 24 24');
+
+ const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
+
+ path.setAttribute('d', CATEGORY_ICONS[this.name_]);
+ path.setAttribute('fill', 'currentColor');
+ svg.appendChild(path);
+ return svg;
+ }
+}
diff --git a/apps/server/Dockerfile b/apps/server/Dockerfile
index 97e48629..002fcfae 100644
--- a/apps/server/Dockerfile
+++ b/apps/server/Dockerfile
@@ -1,11 +1,11 @@
FROM base-image AS backend-build
+
WORKDIR /app/apps/server
+
COPY ./apps/server .
COPY --from=base-image /app/packages /app/packages
+
RUN pnpm install --offline --frozen-lockfile
RUN pnpm run build
-FROM node:20-alpine AS backend
-WORKDIR /app
-COPY --from=backend-build /app/apps/server/dist ./
CMD ["pnpm", "run", "start"]
diff --git a/apps/server/package.json b/apps/server/package.json
index 9283cbf2..c1f4a6c9 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -3,7 +3,7 @@
"version": "1.0.0",
"scripts": {
"dev": "cross-env nodemon --exec ts-node -r tsconfig-paths/register src/index.ts",
- "build": "tsc",
+ "build": "tsc && tsc-alias",
"start": "node dist/index.js",
"swagger-auto": "ts-node src/docs/swaggerAutogen.ts"
},
@@ -25,6 +25,6 @@
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1",
"ts-node": "^10.0.0",
- "tsconfig-paths": "^4.2.0"
+ "tsc-alias": "^1.8.10"
}
}
diff --git a/apps/server/src/config/dbConnection.ts b/apps/server/src/config/dbConnection.ts
index 3681e860..e43a26bf 100644
--- a/apps/server/src/config/dbConnection.ts
+++ b/apps/server/src/config/dbConnection.ts
@@ -3,45 +3,50 @@ import 'dotenv/config';
import { createTunnel } from 'tunnel-ssh';
const setDbConnection = async () => {
- const tunnelOptions = {
- autoClose: true,
- };
-
- const sshOptions = {
- host: process.env.SSH_HOST,
- port: process.env.SSH_PORT,
- username: process.env.SSH_USER,
- password: process.env.SSH_PASSWORD,
- };
-
- const serverOptions = {
- port: parseInt(process.env.LOCAL_PORT || '27018', 10) || 27018,
- };
-
- const forwardOptions = {
- dstAddr: process.env.SSH_DATABASE_HOST,
- dstPort: parseInt(process.env.SSH_DATABASE_PORT || '27017', 10),
- };
+ const isLocal = process.env.IS_LOCAL === 'true';
+
+ if (isLocal) {
+ const tunnelOptions = {
+ autoClose: true,
+ };
+
+ const sshOptions = {
+ host: process.env.SSH_HOST,
+ port: process.env.SSH_PORT,
+ username: process.env.SSH_USER,
+ password: process.env.SSH_PASSWORD,
+ };
+
+ const serverOptions = {
+ port: parseInt(process.env.LOCAL_PORT || '27018', 10) || 27018,
+ };
+
+ const forwardOptions = {
+ dstAddr: process.env.SSH_DATABASE_HOST,
+ dstPort: parseInt(process.env.SSH_DATABASE_PORT || '27017', 10),
+ };
+
+ try {
+ const [server] = await createTunnel(tunnelOptions, serverOptions, sshOptions, forwardOptions);
+
+ const address = server.address();
+ if (address && typeof address !== 'string') {
+ console.log(`SSH 터널이 수신 대기 중입니다.`);
+ } else {
+ console.error('서버 주소를 가져올 수 없습니다.');
+ return;
+ }
+ } catch (error) {
+ console.error('SSH 터널링 오류:', error);
+ return;
+ }
+ }
try {
- const [server, client] = await createTunnel(
- tunnelOptions,
- serverOptions,
- sshOptions,
- forwardOptions
- );
-
- const address = server.address();
- if (address && typeof address !== 'string') {
- console.log(`SSH 터널이 수신 대기 중입니다.`);
-
- await mongoose.connect(process.env.MONGO_URI || '');
- console.log('MongoDB에 성공적으로 연결되었습니다.');
- } else {
- console.error('서버 주소를 가져올 수 없습니다.');
- }
+ await mongoose.connect(process.env.MONGO_URI || '');
+ console.log('MongoDB에 성공적으로 연결되었습니다.');
} catch (error) {
- console.error('SSH 터널링 오류:', error);
+ console.error('MongoDB 연결 오류:', error);
}
};
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7c1f78e6..7b94854f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -196,6 +196,9 @@ importers:
tsconfig-paths:
specifier: ^4.2.0
version: 4.2.0
+ tsc-alias:
+ specifier: ^1.8.10
+ version: 1.8.10
packages/tsconfig: {}
@@ -1353,6 +1356,10 @@ packages:
array-flatten@1.1.1:
resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
+ array-union@2.1.0:
+ resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+ engines: {node: '>=8'}
+
asn1@0.2.6:
resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
@@ -1569,6 +1576,10 @@ packages:
resolution: {integrity: sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==}
engines: {node: '>= 8'}
+ cross-spawn@7.0.5:
+ resolution: {integrity: sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==}
+ engines: {node: '>= 8'}
+
css.escape@1.5.1:
resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
@@ -1654,6 +1665,10 @@ packages:
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
engines: {node: '>=0.3.1'}
+ dir-glob@3.0.1:
+ resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+ engines: {node: '>=8'}
+
dlv@1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
@@ -1951,6 +1966,10 @@ packages:
resolution: {integrity: sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==}
engines: {node: '>=18'}
+ globby@11.1.0:
+ resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+ engines: {node: '>=10'}
+
goober@2.1.16:
resolution: {integrity: sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==}
peerDependencies:
@@ -2341,6 +2360,10 @@ packages:
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+ mylas@2.1.13:
+ resolution: {integrity: sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg==}
+ engines: {node: '>=12.0.0'}
+
mz@2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
@@ -2486,6 +2509,10 @@ packages:
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
engines: {node: '>= 6'}
+ plimit-lit@1.6.1:
+ resolution: {integrity: sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==}
+ engines: {node: '>=12'}
+
polished@4.3.1:
resolution: {integrity: sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==}
engines: {node: '>=10'}
@@ -2634,6 +2661,10 @@ packages:
querystringify@2.2.0:
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
+ queue-lit@1.5.2:
+ resolution: {integrity: sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw==}
+ engines: {node: '>=12'}
+
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -2828,6 +2859,10 @@ packages:
sister@3.0.2:
resolution: {integrity: sha512-p19rtTs+NksBRKW9qn0UhZ8/TUI9BPw9lmtHny+Y3TinWlOa9jWh9xB0AtPSdmOy49NJJJSSe0Ey4C7h0TrcYA==}
+ slash@3.0.0:
+ resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+ engines: {node: '>=8'}
+
snake-case@3.0.4:
resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==}
@@ -3020,6 +3055,10 @@ packages:
'@swc/wasm':
optional: true
+ tsc-alias@1.8.10:
+ resolution: {integrity: sha512-Ibv4KAWfFkFdKJxnWfVtdOmB0Zi1RJVxcbPGiCDsFpCQSsmpWyuzHG3rQyI5YkobWwxFPEyQfu1hdo4qLG2zPw==}
+ hasBin: true
+
tsconfig-paths@4.2.0:
resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==}
engines: {node: '>=6'}
@@ -4446,6 +4485,8 @@ snapshots:
array-flatten@1.1.1: {}
+ array-union@2.1.0: {}
+
asn1@0.2.6:
dependencies:
safer-buffer: 2.1.2
@@ -4619,8 +4660,7 @@ snapshots:
commander@6.2.0: {}
- commander@9.5.0:
- optional: true
+ commander@9.5.0: {}
concat-map@0.0.1: {}
@@ -4678,6 +4718,12 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
+ cross-spawn@7.0.5:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
css.escape@1.5.1: {}
cssesc@3.0.0: {}
@@ -4733,6 +4779,10 @@ snapshots:
diff@4.0.2: {}
+ dir-glob@3.0.1:
+ dependencies:
+ path-type: 4.0.0
+
dlv@1.1.3: {}
doctrine@3.0.0:
@@ -5115,6 +5165,15 @@ snapshots:
globals@15.12.0: {}
+ globby@11.1.0:
+ dependencies:
+ array-union: 2.1.0
+ dir-glob: 3.0.1
+ fast-glob: 3.3.2
+ ignore: 5.3.2
+ merge2: 1.4.1
+ slash: 3.0.0
+
goober@2.1.16(csstype@3.1.3):
dependencies:
csstype: 3.1.3
@@ -5461,6 +5520,8 @@ snapshots:
ms@2.1.3: {}
+ mylas@2.1.13: {}
+
mz@2.7.0:
dependencies:
any-promise: 1.3.0
@@ -5589,6 +5650,10 @@ snapshots:
pirates@4.0.6: {}
+ plimit-lit@1.6.1:
+ dependencies:
+ queue-lit: 1.5.2
+
polished@4.3.1:
dependencies:
'@babel/runtime': 7.26.0
@@ -5676,6 +5741,8 @@ snapshots:
querystringify@2.2.0: {}
+ queue-lit@1.5.2: {}
+
queue-microtask@1.2.3: {}
range-parser@1.2.1: {}
@@ -5911,6 +5978,8 @@ snapshots:
sister@3.0.2: {}
+ slash@3.0.0: {}
+
snake-case@3.0.4:
dependencies:
dot-case: 3.0.4
@@ -6131,6 +6200,15 @@ snapshots:
v8-compile-cache-lib: 3.0.1
yn: 3.1.1
+ tsc-alias@1.8.10:
+ dependencies:
+ chokidar: 3.6.0
+ commander: 9.5.0
+ globby: 11.1.0
+ mylas: 2.1.13
+ normalize-path: 3.0.0
+ plimit-lit: 1.6.1
+
tsconfig-paths@4.2.0:
dependencies:
json5: 2.2.3