+ {/* 헤더 */}
+
파일 선택
+
+ {/* 파일 목록 */}
+
+ {files.map(({ name: fileName }, index) => (
+
+ ))}
+
+
+ {/* 힌트 */}
+
+ ↑↓ 이동 · Enter 선택 · Esc 닫기
+
+
+ );
+}
diff --git a/apps/client/src/widgets/chat/components/ChatPanel.tsx b/apps/client/src/widgets/chat/components/ChatPanel.tsx
index cb2a2f06..3355eefc 100644
--- a/apps/client/src/widgets/chat/components/ChatPanel.tsx
+++ b/apps/client/src/widgets/chat/components/ChatPanel.tsx
@@ -100,7 +100,7 @@ const ChatMessages = memo(function ChatMessages() {
const messages = useChatStore((state) => state.messages);
return (
-
+
);
diff --git a/apps/client/src/widgets/participants/index.tsx b/apps/client/src/widgets/participants/index.tsx
index ba5c060c..dec92435 100644
--- a/apps/client/src/widgets/participants/index.tsx
+++ b/apps/client/src/widgets/participants/index.tsx
@@ -7,7 +7,7 @@ import { usePtsStore } from '@/stores/pts';
import { useRoomStore } from '@/stores/room';
import { useSocketStore } from '@/stores/socket';
import { SOCKET_EVENTS, PERMISSION, ROLE, type Pt } from '@codejam/common';
-import { SidebarHeader, toast } from '@codejam/ui';
+import { SidebarHeader, toast, ScrollArea } from '@codejam/ui';
import type { SortKey } from './lib/types';
import type { FilterOption } from './types';
import { filterParticipants, sortParticipants } from './types';
@@ -109,7 +109,7 @@ export function Participants() {
/>
}
/>
-
@@ -134,12 +134,12 @@ function ParticipantsSection({
}
return (
- <>
+
{me &&
}
{others.length > 0 &&
}
- >
+
);
}
@@ -159,11 +159,11 @@ function Me({ me }: { me?: Pt }) {
function ParticipantList({ others }: { others: Pt[] }) {
return (
-
+
{others.map((p) => (
))}
-
+
);
}
diff --git a/docs/week7-demo-final.pdf b/docs/week7-demo-final.pdf
new file mode 100644
index 00000000..067cfb95
Binary files /dev/null and b/docs/week7-demo-final.pdf differ
diff --git a/packages/ui/src/components/base/index.ts b/packages/ui/src/components/base/index.ts
index 4798a15a..3035fe38 100644
--- a/packages/ui/src/components/base/index.ts
+++ b/packages/ui/src/components/base/index.ts
@@ -62,7 +62,6 @@ export {
InputGroupTextarea,
} from './input-group';
export { Input } from './input';
-export { Popover, PopoverContent, PopoverTrigger } from './popover';
export {
Progress,
ProgressTrack,
@@ -132,3 +131,11 @@ export {
EmptyContent,
EmptyMedia,
} from './empty';
+export {
+ Popover,
+ PopoverContent,
+ PopoverDescription,
+ PopoverHeader,
+ PopoverTitle,
+ PopoverTrigger,
+} from './popover';
diff --git a/packages/ui/src/components/primitives/avatar/avvvatars-avatar.ts b/packages/ui/src/components/primitives/avatar/avvvatars-avatar.ts
index 90a2bd51..a08a4bf1 100644
--- a/packages/ui/src/components/primitives/avatar/avvvatars-avatar.ts
+++ b/packages/ui/src/components/primitives/avatar/avvvatars-avatar.ts
@@ -1,7 +1,7 @@
import { createElement, type ReactNode } from 'react';
-import { renderToStaticMarkup } from 'react-dom/server';
import Avvvatars from './avvvatars/avvvatars.js';
import { getAvatarColors } from '@codejam/common/avvvatars';
+import { SHAPE_PATHS } from './avvvatars/shape-paths.js';
import { type AvatarProvider } from './avatar-generator.js';
export type AvvvatarsVariant = 'shape' | 'character';
@@ -28,51 +28,39 @@ export class AvvvatarsProvider implements AvatarProvider {
}
toSvgString(id: string, size: number): string {
- const html = renderToStaticMarkup(
- createElement(Avvvatars, {
- value: id,
- size,
- variant: this.variant,
- }),
- );
-
- // 색상 정보 가져오기
const colors = getAvatarColors(id);
const bgColor = colors.background;
- const fgColor = this.variant === 'character' ? colors.text : colors.shape;
if (this.variant === 'character') {
- // Character 모드: 배경 원 + 텍스트
const name = String(id).substring(0, 2).toUpperCase();
+ const fgColor = colors.text;
const fontSize = Math.round((size / 100) * 37);
- const svg = `