From 2c9e07b9285980d6985ca97b6ced9f4e7babf56d Mon Sep 17 00:00:00 2001
From: YEONGJAE LEE <71895560+lee0jae330@users.noreply.github.com>
Date: Thu, 5 Dec 2024 12:27:25 +0900
Subject: [PATCH] =?UTF-8?q?[#238]=20=ED=99=88=ED=8E=98=EC=9D=B4=EC=A7=80?=
=?UTF-8?q?=20=EC=B4=88=EA=B8=B0=20=EB=A1=9C=EB=94=A9=20=EC=8B=9C=20?=
=?UTF-8?q?=EC=8A=A4=EC=BC=88=EB=A0=88=ED=86=A4=20UI=20=EC=A0=81=EC=9A=A9?=
=?UTF-8?q?=20=EB=B0=8F=20code-highlighter=20=EC=BB=B4=ED=8F=AC=EB=84=8C?=
=?UTF-8?q?=ED=8A=B8=20=EC=8A=A4=ED=86=A0=EB=A6=AC=EB=B6=81=20=EC=A0=9C?=
=?UTF-8?q?=EC=9E=91=20(#239)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* ๐ chore: ๋ก๋ฉ ์ ์ค์ผ๋ ํค UI ์ถ๊ฐ ๋ฐ ๋ฌดํ์คํฌ๋กค ์ปค์คํ
ํ
์ผ๋ก ๋ถ๋ฆฌ
* โจ feat: ์ฝ๋ high-lighter storybook ์ถ๊ฐ
* ๐ chore: let -> const๋ก ๋ณ๊ฒฝ
---
README.md | 12 +--
.../CodeContent/CodeContent.stories.tsx | 44 ++++++++++
.../{ => CodeContent}/CodeContent.tsx | 10 ++-
.../CodeViewer/CodeViewer.stories.tsx | 82 +++++++++++++++++++
.../{ => CodeViewer}/CodeViewer.tsx | 15 ++--
.../LineNumbers/LineNumber.stories.tsx | 22 +++++
.../{ => LineNumbers}/LineNumbers.tsx | 7 +-
.../src/shared/code-highlighter/index.ts | 2 +-
apps/client/src/shared/hooks/index.ts | 1 +
.../src/shared/hooks/useInfiniteScroll.ts | 29 +++++++
.../hooks/usePreventLeaveWorkspacePage.ts | 2 +-
.../WorkspaceContainer/WorkspaceContainer.tsx | 44 ++++------
12 files changed, 226 insertions(+), 44 deletions(-)
create mode 100644 apps/client/src/shared/code-highlighter/components/CodeContent/CodeContent.stories.tsx
rename apps/client/src/shared/code-highlighter/components/{ => CodeContent}/CodeContent.tsx (91%)
create mode 100644 apps/client/src/shared/code-highlighter/components/CodeViewer/CodeViewer.stories.tsx
rename apps/client/src/shared/code-highlighter/components/{ => CodeViewer}/CodeViewer.tsx (75%)
create mode 100644 apps/client/src/shared/code-highlighter/components/LineNumbers/LineNumber.stories.tsx
rename apps/client/src/shared/code-highlighter/components/{ => LineNumbers}/LineNumbers.tsx (86%)
create mode 100644 apps/client/src/shared/hooks/useInfiniteScroll.ts
diff --git a/README.md b/README.md
index 04510bc7..8d7ef2a9 100644
--- a/README.md
+++ b/README.md
@@ -60,15 +60,14 @@
hello world!
```
-์น ๊ฐ๋ฐ ์ด๋ณด์๋ค์๊ฒ ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ฒ์ ์ด๋ ต๊ณ ๋ถ๋ด์ค๋ฝ๊ฒ ๋๊ปด์ง ์ ์์ต๋๋ค.
-ํ์ง๋ง BooLock์์๋ ๋ธ๋ก์ ์กฐ๋ฆฝํ๋ฉฐ ์ฝ๊ณ ์ฌ๋ฏธ์๊ฒ ์์ ๋ง์ ์น์ฌ์ดํธ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
+์น ๊ฐ๋ฐ ์ด๋ณด์๋ค์๊ฒ ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ฒ์ ์ด๋ ต๊ณ ๋ถ๋ด์ค๋ฝ๊ฒ ๋๊ปด์ง ์ ์์ต๋๋ค.
+ํ์ง๋ง BooLock์์๋ ๋ธ๋ก์ ์กฐ๋ฆฝํ๋ฉฐ ์ฝ๊ณ ์ฌ๋ฏธ์๊ฒ ์์ ๋ง์ ์น์ฌ์ดํธ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
-BooLock์ HTML๊ณผ CSS๋ฅผ ๋ธ๋ก์ฝ๋ฉ ๋ฐฉ์์ผ๋ก ํ์ตํ ์ ์๋ ํ๋ซํผ์
๋๋ค.
-์ฝ๋๋ฅผ ๋ชฐ๋ผ๋ ๋ธ๋ก์ ์กฐ๋ฆฝํ๋ ๊ฐ๋จํ ๋ฐฉ์์ผ๋ก ์ํ๋ ์น์ฌ์ดํธ๋ฅผ ์ ์ํ๊ณ , ์ด๋ฅผ ํตํด ์น ๊ฐ๋ฐ์ ๊ธฐ์ด๋ฅผ ์ฌ๋ฏธ์๊ฒ ๋ฐฐ์ธ ์ ์์ต๋๋ค.
+BooLock์ HTML๊ณผ CSS๋ฅผ ๋ธ๋ก์ฝ๋ฉ ๋ฐฉ์์ผ๋ก ํ์ตํ ์ ์๋ ํ๋ซํผ์
๋๋ค.
+์ฝ๋๋ฅผ ๋ชฐ๋ผ๋ ๋ธ๋ก์ ์กฐ๋ฆฝํ๋ ๊ฐ๋จํ ๋ฐฉ์์ผ๋ก ์ํ๋ ์น์ฌ์ดํธ๋ฅผ ์ ์ํ๊ณ , ์ด๋ฅผ ํตํด ์น ๊ฐ๋ฐ์ ๊ธฐ์ด๋ฅผ ์ฌ๋ฏธ์๊ฒ ๋ฐฐ์ธ ์ ์์ต๋๋ค.
๋ธ๋ก๋ค์ด ๋ชจ์ฌ ๋ง๋ค์ด์ง ๋๋ง์ ์นํ์ด์ง๋ฅผ ์ฃผ๋ณ ์ฌ๋๋ค๊ณผ ๊ณต์ ํด๋ณด์ธ์. โค๏ธ
-
# ๐ฅ ์ฃผ์๊ธฐ๋ฅ
@@ -184,7 +183,7 @@ BooLock์ HTML๊ณผ CSS๋ฅผ ๋ธ๋ก์ฝ๋ฉ ๋ฐฉ์์ผ๋ก ํ์ตํ ์ ์๋ ํ๋ซ
- Blockly์ Flyout ๋ด๋ถ์ DOM ์์(input, button)๋ฅผ ๋์ ์ผ๋ก ์์ฑํ์ฌ ์ฌ์ฉ์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌ์ฑํ์ต๋๋ค. ์
๋ ฅ๊ฐ์ ์ค๋ณต ํ์ธ๊ณผ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ๊ฑฐ์ณ CSS_ ์ ๋์ฌ๋ฅผ ๋ถ์ฌ ๋ธ๋ก์ผ๋ก ๋ฑ๋ก๋๋ฉฐ, ์ฆ์ Flyout์ ๋ฐ์๋ฉ๋๋ค. ์์ฑ๋ ๋ธ๋ก์ ์ฐํด๋ฆญ ์ "๋ธ๋ก ์ญ์ " ์ต์
์ผ๋ก ๊ด๋ จ๋ ๋ชจ๋ ์ธ์คํด์ค๋ฅผ ์ญ์ ํ ์ ์์ต๋๋ค. Reset CSS ์ฒดํฌ๋ฐ์ค์ ํดํ์ ์ถ๊ฐํด ๊ธฐ๋ณธ ์คํ์ผ ์ด๊ธฐํ์ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ์ต๋๋ค.
+ Blockly์ Flyout ๋ด๋ถ์ DOM ์์(input, button)๋ฅผ ๋์ ์ผ๋ก ์์ฑํ์ฌ ์ฌ์ฉ์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌ์ฑํ์ต๋๋ค. ์
๋ ฅ๊ฐ์ ์ค๋ณต ํ์ธ๊ณผ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ๊ฑฐ์ณ CSS\_ ์ ๋์ฌ๋ฅผ ๋ถ์ฌ ๋ธ๋ก์ผ๋ก ๋ฑ๋ก๋๋ฉฐ, ์ฆ์ Flyout์ ๋ฐ์๋ฉ๋๋ค. ์์ฑ๋ ๋ธ๋ก์ ์ฐํด๋ฆญ ์ "๋ธ๋ก ์ญ์ " ์ต์
์ผ๋ก ๊ด๋ จ๋ ๋ชจ๋ ์ธ์คํด์ค๋ฅผ ์ญ์ ํ ์ ์์ต๋๋ค. Reset CSS ์ฒดํฌ๋ฐ์ค์ ํดํ์ ์ถ๊ฐํด ๊ธฐ๋ณธ ์คํ์ผ ์ด๊ธฐํ์ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ์ต๋๋ค.
> **๐ ๋ ์์ธํ ๊ธฐ๋ก ๋ฐ ๊ณผ์ ํ์ธํ๊ธฐ ๐**
> [Blockly ์ปค์คํ
](https://www.notion.so/Blockly-14077ba9a1b680ccafcbd5b3781bf390?pvs=21)
@@ -268,6 +267,7 @@ React์ SPA ๊ตฌ์กฐ๋ก ์ธํด ๊ฒ์ ์์ง์ด ํ์ด์ง ์ ๋ณด๋ฅผ ์ธ์ํ์ง
> **๐ ๋ ์์ธํ ๊ธฐ๋ก ๋ฐ ๊ณผ์ ํ์ธํ๊ธฐ ๐**
> [์ฌ์ฉ์ ๊ฐ์ด๋](https://www.notion.so/51679d3e288b485f9a0ea9068eb621f5?pvs=21)
### ์คํ ๋ฆฌ๋ถ ํ
์คํธ
+
[**์คํ ๋ฆฌ๋ถ ๋ฐฐํฌ ๋งํฌ**](https://boostcampwm-2024.github.io/web31-BooLock/)
diff --git a/apps/client/src/shared/code-highlighter/components/CodeContent/CodeContent.stories.tsx b/apps/client/src/shared/code-highlighter/components/CodeContent/CodeContent.stories.tsx
new file mode 100644
index 00000000..54641cec
--- /dev/null
+++ b/apps/client/src/shared/code-highlighter/components/CodeContent/CodeContent.stories.tsx
@@ -0,0 +1,44 @@
+import { Meta, StoryObj } from '@storybook/react';
+
+import { CodeContent } from './CodeContent';
+
+const meta: Meta
= {
+ title: 'shared/code-highlighter/CodeContent',
+ component: CodeContent,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+};
+
+export default meta;
+
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ code: `
+
+
+
+
+ `,
+ codeLineList: [
+ '',
+ ' ',
+ ' ',
+ ' ',
+ '
title
',
+ '
content
',
+ '
',
+ ' ',
+ '',
+ ],
+ selectedBlockStartLine: 5,
+ selectedBlockLength: 7,
+ selectedBlockType: 'BOOLOCK_SYSTEM_html',
+ },
+};
diff --git a/apps/client/src/shared/code-highlighter/components/CodeContent.tsx b/apps/client/src/shared/code-highlighter/components/CodeContent/CodeContent.tsx
similarity index 91%
rename from apps/client/src/shared/code-highlighter/components/CodeContent.tsx
rename to apps/client/src/shared/code-highlighter/components/CodeContent/CodeContent.tsx
index ded836c6..c58cd515 100644
--- a/apps/client/src/shared/code-highlighter/components/CodeContent.tsx
+++ b/apps/client/src/shared/code-highlighter/components/CodeContent/CodeContent.tsx
@@ -1,5 +1,6 @@
-import styles from '../styles/CodeViewer.module.css';
-import { useState, useEffect } from 'react';
+import { useEffect, useState } from 'react';
+
+import styles from '../../styles/CodeViewer.module.css';
type CodeViewerProps = {
code: string;
@@ -9,6 +10,11 @@ type CodeViewerProps = {
selectedBlockType?: string | null;
};
+/**
+ *
+ * @description
+ * ๋ณํ๋ HTML, CSS ์ฝ๋๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ปดํฌ๋ํธ
+ */
export const CodeContent = ({
code,
codeLineList,
diff --git a/apps/client/src/shared/code-highlighter/components/CodeViewer/CodeViewer.stories.tsx b/apps/client/src/shared/code-highlighter/components/CodeViewer/CodeViewer.stories.tsx
new file mode 100644
index 00000000..2a7c1d07
--- /dev/null
+++ b/apps/client/src/shared/code-highlighter/components/CodeViewer/CodeViewer.stories.tsx
@@ -0,0 +1,82 @@
+import { Meta, StoryObj } from '@storybook/react';
+
+import { CodeViewer } from './CodeViewer';
+
+const meta: Meta = {
+ title: 'shared/code-highlighter/CodeViewer',
+ component: CodeViewer,
+ parameters: {
+ layout: 'fullscreen',
+ },
+ tags: ['autodocs'],
+};
+
+export default meta;
+
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ code: `
+
+
+
+
+ `,
+ type: 'html',
+ theme: 'light',
+ },
+};
+
+export const DarkThemeHTML: Story = {
+ args: {
+ code: `
+
+
+
+
+ `,
+ type: 'html',
+ theme: 'dark',
+ },
+};
+
+export const LightThemeCss: Story = {
+ args: {
+ code: `.title {
+ background-color: red;
+ }
+ .content {
+ font-size: 16px;
+ font-weight: bold;
+ font-family: 'Arial';
+ color: #000;
+ }
+ `,
+ type: 'css',
+ theme: 'light',
+ },
+};
+
+export const DarkThemeCss: Story = {
+ args: {
+ code: `.title {
+ background-color: red;
+ }
+ .content {
+ font-size: 16px;
+ font-weight: bold;
+ font-family: 'Arial';
+ color: #000;
+ }
+ `,
+ type: 'css',
+ theme: 'dark',
+ },
+};
diff --git a/apps/client/src/shared/code-highlighter/components/CodeViewer.tsx b/apps/client/src/shared/code-highlighter/components/CodeViewer/CodeViewer.tsx
similarity index 75%
rename from apps/client/src/shared/code-highlighter/components/CodeViewer.tsx
rename to apps/client/src/shared/code-highlighter/components/CodeViewer/CodeViewer.tsx
index e29d86b2..490635ad 100644
--- a/apps/client/src/shared/code-highlighter/components/CodeViewer.tsx
+++ b/apps/client/src/shared/code-highlighter/components/CodeViewer/CodeViewer.tsx
@@ -1,8 +1,8 @@
-import { CodeContent } from './CodeContent';
-import { LineNumbers } from './LineNumbers';
-import { parseHighlightCss } from '../utils/parseHighlightCss';
-import { parseHighlightHtml } from '../utils/parseHighlightHtml';
-import styles from '../styles/CodeViewer.module.css';
+import { CodeContent } from '../CodeContent/CodeContent';
+import { LineNumbers } from '../LineNumbers/LineNumbers';
+import { parseHighlightCss } from '../../utils/parseHighlightCss';
+import { parseHighlightHtml } from '../../utils/parseHighlightHtml';
+import styles from '../../styles/CodeViewer.module.css';
import { useCoachMarkStore } from '@/shared/store/useCoachMarkStore';
type CodeViewerProps = {
@@ -14,6 +14,11 @@ type CodeViewerProps = {
selectedBlockType?: string | null;
};
+/**
+ *
+ * @description
+ * ๋ณํ๋ HTML, CSS ์ฝ๋๋ฅผ ์ค ์์ ํจ๊ป ๋ณด์ฌ์ฃผ๋ ์ปดํฌ๋ํธ
+ */
export const CodeViewer = ({
code,
type,
diff --git a/apps/client/src/shared/code-highlighter/components/LineNumbers/LineNumber.stories.tsx b/apps/client/src/shared/code-highlighter/components/LineNumbers/LineNumber.stories.tsx
new file mode 100644
index 00000000..c996d2c3
--- /dev/null
+++ b/apps/client/src/shared/code-highlighter/components/LineNumbers/LineNumber.stories.tsx
@@ -0,0 +1,22 @@
+import { Meta, StoryObj } from '@storybook/react';
+
+import { LineNumbers } from './LineNumbers';
+
+const meta: Meta = {
+ title: 'shared/code-highlighter/LineNumbers',
+ component: LineNumbers,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+};
+
+export default meta;
+
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ codeLineList: ['line1', 'line2', 'line3'],
+ },
+};
diff --git a/apps/client/src/shared/code-highlighter/components/LineNumbers.tsx b/apps/client/src/shared/code-highlighter/components/LineNumbers/LineNumbers.tsx
similarity index 86%
rename from apps/client/src/shared/code-highlighter/components/LineNumbers.tsx
rename to apps/client/src/shared/code-highlighter/components/LineNumbers/LineNumbers.tsx
index 19f0df11..69a77d28 100644
--- a/apps/client/src/shared/code-highlighter/components/LineNumbers.tsx
+++ b/apps/client/src/shared/code-highlighter/components/LineNumbers/LineNumbers.tsx
@@ -1,10 +1,15 @@
+import styles from '../../styles/CodeViewer.module.css';
import { useState } from 'react';
-import styles from '../styles/CodeViewer.module.css';
type LineNumbersProps = {
codeLineList: string[];
};
+/**
+ *
+ * @description
+ * ์ฝ๋์ ์ค ์๋ฅผ ํ์ํ๋ ์ปดํฌ๋ํธ
+ */
export const LineNumbers = ({ codeLineList }: LineNumbersProps) => {
const [hoveredLineNumber, setHoveredLineNumber] = useState(null);
diff --git a/apps/client/src/shared/code-highlighter/index.ts b/apps/client/src/shared/code-highlighter/index.ts
index 96758797..45187a73 100644
--- a/apps/client/src/shared/code-highlighter/index.ts
+++ b/apps/client/src/shared/code-highlighter/index.ts
@@ -1 +1 @@
-export { CodeViewer } from './components/CodeViewer';
+export { CodeViewer } from './components/CodeViewer/CodeViewer';
diff --git a/apps/client/src/shared/hooks/index.ts b/apps/client/src/shared/hooks/index.ts
index 1ce64c92..94bde057 100644
--- a/apps/client/src/shared/hooks/index.ts
+++ b/apps/client/src/shared/hooks/index.ts
@@ -15,3 +15,4 @@ export { useCssOptionItem } from './css/useCssOptionItem';
export { workspaceKeys } from './query-key/workspaceKeys';
export { usePreventLeaveWorkspacePage } from './usePreventLeaveWorkspacePage';
+export { useInfiniteScroll } from './useInfiniteScroll';
diff --git a/apps/client/src/shared/hooks/useInfiniteScroll.ts b/apps/client/src/shared/hooks/useInfiniteScroll.ts
new file mode 100644
index 00000000..5f839454
--- /dev/null
+++ b/apps/client/src/shared/hooks/useInfiniteScroll.ts
@@ -0,0 +1,29 @@
+import { useEffect, useRef } from 'react';
+
+type useInfiniteScrollProps = {
+ intersectionCallback: IntersectionObserverCallback;
+};
+
+export const useInfiniteScroll = ({ intersectionCallback }: useInfiniteScrollProps) => {
+ const targetRef = useRef(null);
+
+ const option = {
+ root: null,
+ rootMargin: '0px',
+ threshold: 0.5,
+ };
+
+ useEffect(() => {
+ if (!targetRef.current) {
+ return;
+ }
+ const observer = new IntersectionObserver(intersectionCallback, option);
+ observer.observe(targetRef.current);
+ return () => {
+ if (targetRef.current) {
+ observer.unobserve(targetRef.current);
+ }
+ };
+ }, [intersectionCallback]);
+ return targetRef;
+};
diff --git a/apps/client/src/shared/hooks/usePreventLeaveWorkspacePage.ts b/apps/client/src/shared/hooks/usePreventLeaveWorkspacePage.ts
index 34c4bb2c..de4c4adf 100644
--- a/apps/client/src/shared/hooks/usePreventLeaveWorkspacePage.ts
+++ b/apps/client/src/shared/hooks/usePreventLeaveWorkspacePage.ts
@@ -4,7 +4,7 @@ import { useWorkspaceChangeStatusStore } from '@/shared/store';
export const usePreventLeaveWorkspacePage = () => {
const { isBlockChanged, isCssChanged } = useWorkspaceChangeStatusStore();
- let blocker = useBlocker(
+ const blocker = useBlocker(
({ currentLocation, nextLocation }) =>
currentLocation.pathname !== nextLocation.pathname && (isBlockChanged || isCssChanged)
);
diff --git a/apps/client/src/widgets/home/WorkspaceContainer/WorkspaceContainer.tsx b/apps/client/src/widgets/home/WorkspaceContainer/WorkspaceContainer.tsx
index 16e6cf67..491b760a 100644
--- a/apps/client/src/widgets/home/WorkspaceContainer/WorkspaceContainer.tsx
+++ b/apps/client/src/widgets/home/WorkspaceContainer/WorkspaceContainer.tsx
@@ -1,9 +1,8 @@
import { EmptyWorkspace, WorkspaceGrid, WorkspaceHeader, WorkspaceList } from '@/widgets';
-import { useEffect, useRef } from 'react';
+import { useGetWorkspaceList, useInfiniteScroll } from '@/shared/hooks';
import { SkeletonWorkspaceList } from '@/shared/ui';
import { WorkspaceLoadError } from '@/entities';
-import { useGetWorkspaceList } from '@/shared/hooks';
/**
*
@@ -14,36 +13,25 @@ export const WorkspaceContainer = () => {
const { hasNextPage, fetchNextPage, isPending, isFetchingNextPage, isError, workspaceList } =
useGetWorkspaceList();
- const nextFetchTargetRef = useRef(null);
-
- useEffect(() => {
- const options = {
- root: null,
- rootMargin: '0px',
- threshold: 0.5,
- };
- const fetchCallback: IntersectionObserverCallback = (entries, observer) => {
- entries.forEach((entry) => {
- if (entry.isIntersecting && hasNextPage) {
- fetchNextPage();
- observer.unobserve(entry.target);
- }
- });
- };
- const observer = new IntersectionObserver(fetchCallback, options);
- if (nextFetchTargetRef.current) {
- observer.observe(nextFetchTargetRef.current);
- }
- return () => {
- if (nextFetchTargetRef.current) {
- observer.unobserve(nextFetchTargetRef.current);
+ const fetchCallback: IntersectionObserverCallback = (entries, observer) => {
+ entries.forEach((entry) => {
+ if (entry.isIntersecting && hasNextPage) {
+ fetchNextPage();
+ observer.unobserve(entry.target);
}
- };
- }, [workspaceList]);
+ });
+ };
+
+ const nextFetchTargetRef = useInfiniteScroll({ intersectionCallback: fetchCallback });
return (
+ {isPending && (
+
+
+
+ )}
{isError ? (
) : (
@@ -53,7 +41,7 @@ export const WorkspaceContainer = () => {
) : (
- {(isPending || isFetchingNextPage) && }
+ {isFetchingNextPage && }
))
)}