@xrift/world-components 0.20.1 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/TagBoard/components/TagChip.d.ts +12 -0
- package/dist/components/TagBoard/components/TagChip.d.ts.map +1 -0
- package/dist/components/TagBoard/components/TagChip.js +13 -0
- package/dist/components/TagBoard/components/TagChip.js.map +1 -0
- package/dist/components/TagBoard/components/TagDisplay/index.d.ts +3 -0
- package/dist/components/TagBoard/components/TagDisplay/index.d.ts.map +1 -0
- package/dist/components/TagBoard/components/TagDisplay/index.js +64 -0
- package/dist/components/TagBoard/components/TagDisplay/index.js.map +1 -0
- package/dist/components/TagBoard/components/TagDisplay/utils.d.ts +23 -0
- package/dist/components/TagBoard/components/TagDisplay/utils.d.ts.map +1 -0
- package/dist/components/TagBoard/components/TagDisplay/utils.js +53 -0
- package/dist/components/TagBoard/components/TagDisplay/utils.js.map +1 -0
- package/dist/components/TagBoard/components/TagSelector/components/ActionButton.d.ts +13 -0
- package/dist/components/TagBoard/components/TagSelector/components/ActionButton.d.ts.map +1 -0
- package/dist/components/TagBoard/components/TagSelector/components/ActionButton.js +12 -0
- package/dist/components/TagBoard/components/TagSelector/components/ActionButton.js.map +1 -0
- package/dist/components/TagBoard/components/TagSelector/components/TagButton.d.ts +12 -0
- package/dist/components/TagBoard/components/TagSelector/components/TagButton.d.ts.map +1 -0
- package/dist/components/TagBoard/components/TagSelector/components/TagButton.js +13 -0
- package/dist/components/TagBoard/components/TagSelector/components/TagButton.js.map +1 -0
- package/dist/components/TagBoard/components/TagSelector/index.d.ts +3 -0
- package/dist/components/TagBoard/components/TagSelector/index.d.ts.map +1 -0
- package/dist/components/TagBoard/components/TagSelector/index.js +57 -0
- package/dist/components/TagBoard/components/TagSelector/index.js.map +1 -0
- package/dist/components/TagBoard/components/TagSelector/utils.d.ts +21 -0
- package/dist/components/TagBoard/components/TagSelector/utils.d.ts.map +1 -0
- package/dist/components/TagBoard/components/TagSelector/utils.js +50 -0
- package/dist/components/TagBoard/components/TagSelector/utils.js.map +1 -0
- package/dist/components/TagBoard/constants.d.ts +8 -0
- package/dist/components/TagBoard/constants.d.ts.map +1 -0
- package/dist/components/TagBoard/constants.js +15 -0
- package/dist/components/TagBoard/constants.js.map +1 -0
- package/dist/components/TagBoard/index.d.ts +4 -0
- package/dist/components/TagBoard/index.d.ts.map +1 -0
- package/dist/components/TagBoard/index.js +25 -0
- package/dist/components/TagBoard/index.js.map +1 -0
- package/dist/components/TagBoard/types.d.ts +46 -0
- package/dist/components/TagBoard/types.d.ts.map +1 -0
- package/dist/components/TagBoard/types.js.map +1 -0
- package/dist/components/TagBoard/utils.d.ts +7 -0
- package/dist/components/TagBoard/utils.d.ts.map +1 -0
- package/dist/components/TagBoard/utils.js +20 -0
- package/dist/components/TagBoard/utils.js.map +1 -0
- package/dist/hooks/useInstanceState.d.ts.map +1 -1
- package/dist/hooks/useInstanceState.js +3 -3
- package/dist/hooks/useInstanceState.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/components/RichVideoPlayer/ControlPanel.d.ts +0 -3
- package/dist/components/RichVideoPlayer/ControlPanel.d.ts.map +0 -1
- package/dist/components/RichVideoPlayer/ControlPanel.js +0 -22
- package/dist/components/RichVideoPlayer/ControlPanel.js.map +0 -1
- package/dist/components/RichVideoPlayer/PlayPauseButton.d.ts +0 -3
- package/dist/components/RichVideoPlayer/PlayPauseButton.d.ts.map +0 -1
- package/dist/components/RichVideoPlayer/PlayPauseButton.js +0 -9
- package/dist/components/RichVideoPlayer/PlayPauseButton.js.map +0 -1
- package/dist/components/RichVideoPlayer/ProgressBar.d.ts +0 -3
- package/dist/components/RichVideoPlayer/ProgressBar.d.ts.map +0 -1
- package/dist/components/RichVideoPlayer/ProgressBar.js +0 -20
- package/dist/components/RichVideoPlayer/ProgressBar.js.map +0 -1
- package/dist/components/RichVideoPlayer/UrlInputButton.d.ts +0 -3
- package/dist/components/RichVideoPlayer/UrlInputButton.d.ts.map +0 -1
- package/dist/components/RichVideoPlayer/UrlInputButton.js +0 -23
- package/dist/components/RichVideoPlayer/UrlInputButton.js.map +0 -1
- package/dist/components/RichVideoPlayer/VolumeControl.d.ts +0 -3
- package/dist/components/RichVideoPlayer/VolumeControl.d.ts.map +0 -1
- package/dist/components/RichVideoPlayer/VolumeControl.js +0 -26
- package/dist/components/RichVideoPlayer/VolumeControl.js.map +0 -1
- package/dist/components/RichVideoPlayer/hooks.d.ts +0 -5
- package/dist/components/RichVideoPlayer/hooks.d.ts.map +0 -1
- package/dist/components/RichVideoPlayer/hooks.js +0 -9
- package/dist/components/RichVideoPlayer/hooks.js.map +0 -1
- package/dist/components/RichVideoPlayer/index.d.ts +0 -4
- package/dist/components/RichVideoPlayer/index.d.ts.map +0 -1
- package/dist/components/RichVideoPlayer/index.js +0 -100
- package/dist/components/RichVideoPlayer/index.js.map +0 -1
- package/dist/components/RichVideoPlayer/types.d.ts +0 -64
- package/dist/components/RichVideoPlayer/types.d.ts.map +0 -1
- package/dist/components/RichVideoPlayer/types.js.map +0 -1
- package/dist/components/RichVideoPlayer/utils.d.ts +0 -32
- package/dist/components/RichVideoPlayer/utils.d.ts.map +0 -1
- package/dist/components/RichVideoPlayer/utils.js +0 -37
- package/dist/components/RichVideoPlayer/utils.js.map +0 -1
- package/dist/components/RichVideoPlayer/utils.test.d.ts +0 -2
- package/dist/components/RichVideoPlayer/utils.test.d.ts.map +0 -1
- package/dist/components/RichVideoPlayer/utils.test.js +0 -109
- package/dist/components/RichVideoPlayer/utils.test.js.map +0 -1
- package/dist/hooks/useVideoScreenControls.d.ts +0 -57
- package/dist/hooks/useVideoScreenControls.d.ts.map +0 -1
- package/dist/hooks/useVideoScreenControls.js +0 -130
- package/dist/hooks/useVideoScreenControls.js.map +0 -1
- package/dist/scenes/SpawnPointTestScene.d.ts +0 -6
- package/dist/scenes/SpawnPointTestScene.d.ts.map +0 -1
- package/dist/scenes/SpawnPointTestScene.js +0 -12
- package/dist/scenes/SpawnPointTestScene.js.map +0 -1
- package/dist/scenes/TestScene.d.ts +0 -6
- package/dist/scenes/TestScene.d.ts.map +0 -1
- package/dist/scenes/TestScene.js +0 -19
- package/dist/scenes/TestScene.js.map +0 -1
- package/dist/scenes/TheaterScene.d.ts +0 -6
- package/dist/scenes/TheaterScene.d.ts.map +0 -1
- package/dist/scenes/TheaterScene.js +0 -12
- package/dist/scenes/TheaterScene.js.map +0 -1
- package/dist/scenes/VideoControlTest.d.ts +0 -5
- package/dist/scenes/VideoControlTest.d.ts.map +0 -1
- package/dist/scenes/VideoControlTest.js +0 -17
- package/dist/scenes/VideoControlTest.js.map +0 -1
- /package/dist/components/{RichVideoPlayer → TagBoard}/types.js +0 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Tag } from '../types';
|
|
2
|
+
export interface TagChipProps {
|
|
3
|
+
tag: Tag;
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
fontSize: number;
|
|
7
|
+
position?: [number, number, number];
|
|
8
|
+
/** 裏面にもテキストを表示するか */
|
|
9
|
+
doubleSided?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare const TagChip: ({ tag, width, height, fontSize, position, doubleSided, }: TagChipProps) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=TagChip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TagChip.d.ts","sourceRoot":"","sources":["../../../../src/components/TagBoard/components/TagChip.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAEnC,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,GAAG,CAAA;IACR,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,qBAAqB;IACrB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,eAAO,MAAM,OAAO,GAAI,0DAOrB,YAAY,4CAoCd,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* TagChip コンポーネント
|
|
4
|
+
*
|
|
5
|
+
* タグを表示するシンプルなチップUI。
|
|
6
|
+
* 色付きのプレーン + 表裏両面にラベルテキストを表示します。
|
|
7
|
+
*/
|
|
8
|
+
import { Text } from '@react-three/drei';
|
|
9
|
+
import { DoubleSide } from 'three';
|
|
10
|
+
export const TagChip = ({ tag, width, height, fontSize, position, doubleSided = false, }) => {
|
|
11
|
+
return (_jsxs("group", { position: position, children: [_jsxs("mesh", { children: [_jsx("planeGeometry", { args: [width, height] }), _jsx("meshBasicMaterial", { color: tag.color, side: DoubleSide })] }), _jsx(Text, { position: [0, 0, 0.01], fontSize: fontSize, color: 0xffffff, anchorX: "center", anchorY: "middle", outlineWidth: fontSize * 0.04, outlineColor: 0x000000, children: tag.label }), doubleSided && (_jsx(Text, { position: [0, 0, -0.02], fontSize: fontSize, anchorX: "center", anchorY: "middle", color: 0xffffff, outlineWidth: fontSize * 0.04, outlineColor: 0x000000, children: tag.label }))] }));
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=TagChip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TagChip.js","sourceRoot":"","sources":["../../../../src/components/TagBoard/components/TagChip.tsx"],"names":[],"mappings":";AAAA;;;;;GAKG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAclC,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,EACtB,GAAG,EACH,KAAK,EACL,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,WAAW,GAAG,KAAK,GACN,EAAE,EAAE;IACjB,OAAO,CACL,iBAAO,QAAQ,EAAE,QAAQ,aAEvB,2BACE,wBAAe,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,GAAI,EACxC,4BAAmB,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,UAAU,GAAI,IACpD,EAEP,KAAC,IAAI,IACH,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EACtB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,QAAQ,EACf,OAAO,EAAC,QAAQ,EAChB,OAAO,EAAC,QAAQ,EAChB,YAAY,EAAE,QAAQ,GAAG,IAAI,EAC7B,YAAY,EAAE,QAAQ,YAErB,GAAG,CAAC,KAAK,GACL,EAEN,WAAW,IAAI,CACd,KAAC,IAAI,IACH,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EACvB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAC,QAAQ,EAChB,OAAO,EAAC,QAAQ,EAChB,KAAK,EAAE,QAAQ,EACf,YAAY,EAAE,QAAQ,GAAG,IAAI,EAC7B,YAAY,EAAE,QAAQ,YAErB,GAAG,CAAC,KAAK,GACL,CACR,IACK,CACT,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/TagBoard/components/TagDisplay/index.tsx"],"names":[],"mappings":"AAoBA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AASnD,eAAO,MAAM,UAAU,GAAI,2DAMxB,eAAe,mDA8FjB,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* TagDisplay コンポーネント
|
|
4
|
+
*
|
|
5
|
+
* 指定ユーザーの頭上に選択済みタグを列ごとに整列して表示します。
|
|
6
|
+
* 位置は `getMovement(userId)` の結果に追従します。
|
|
7
|
+
*
|
|
8
|
+
* Props:
|
|
9
|
+
* - userId: 表示対象ユーザーID
|
|
10
|
+
* - getMovement: ユーザー位置を取得する関数(毎フレーム呼び出し)
|
|
11
|
+
* - tags: 全タグ定義(フィルター前)
|
|
12
|
+
* - visible: 表示/非表示フラグ
|
|
13
|
+
* - instanceStateKey: インスタンス状態キーの識別子
|
|
14
|
+
*/
|
|
15
|
+
import { useMemo, useRef } from "react";
|
|
16
|
+
import { Billboard } from "@react-three/drei";
|
|
17
|
+
import { useFrame } from "@react-three/fiber";
|
|
18
|
+
import { DoubleSide, Vector3 } from "three";
|
|
19
|
+
import { useInstanceState } from "../../../../hooks/useInstanceState";
|
|
20
|
+
import { TagChip } from "../TagChip";
|
|
21
|
+
import { calculateLayout, getSelectedTags, groupTagsByColumn, } from "./utils";
|
|
22
|
+
const HEAD_OFFSET_Y = 1.6;
|
|
23
|
+
export const TagDisplay = ({ userId, getMovement, tags, visible, instanceStateKey, }) => {
|
|
24
|
+
const groupRef = useRef(null);
|
|
25
|
+
const stateKey = `tag-${instanceStateKey}-${userId}`;
|
|
26
|
+
// インスタンス状態から選択済みタグID を取得
|
|
27
|
+
const [selectedTagIds] = useInstanceState(stateKey, []);
|
|
28
|
+
// useMemo
|
|
29
|
+
const flatTags = useMemo(() => tags.flat(), [tags]);
|
|
30
|
+
const selectedTags = useMemo(() => getSelectedTags(selectedTagIds, flatTags), [selectedTagIds, flatTags]);
|
|
31
|
+
const activeColumns = useMemo(() => groupTagsByColumn(selectedTags, tags), [selectedTags, tags]);
|
|
32
|
+
const layout = useMemo(() => calculateLayout(activeColumns), [activeColumns]);
|
|
33
|
+
// useFrame で位置を更新
|
|
34
|
+
useFrame(() => {
|
|
35
|
+
if (!userId || !groupRef.current)
|
|
36
|
+
return;
|
|
37
|
+
const movement = getMovement(userId);
|
|
38
|
+
if (!movement) {
|
|
39
|
+
groupRef.current.visible = false;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// ワールド座標
|
|
43
|
+
const worldPos = new Vector3(movement.position.x, movement.position.y + HEAD_OFFSET_Y, movement.position.z);
|
|
44
|
+
// 親がある場合、ワールド座標をローカル座標に変換
|
|
45
|
+
const parent = groupRef.current.parent;
|
|
46
|
+
if (parent) {
|
|
47
|
+
parent.updateWorldMatrix(true, false);
|
|
48
|
+
parent.worldToLocal(worldPos);
|
|
49
|
+
}
|
|
50
|
+
groupRef.current.position.copy(worldPos);
|
|
51
|
+
groupRef.current.visible = true;
|
|
52
|
+
});
|
|
53
|
+
// タグが無い、または非表示の場合は何も描画しない
|
|
54
|
+
if (selectedTags.length === 0 || !visible)
|
|
55
|
+
return null;
|
|
56
|
+
return (_jsx("group", { ref: groupRef, visible: false, scale: [0.5, 0.5, 0.5], children: _jsx(Billboard, { follow: true, lockX: false, lockY: false, lockZ: false, children: _jsxs("group", { children: [_jsxs("mesh", { position: [0, (-(layout.maxRows - 1) * layout.tagHeight) / 2, -0.02], children: [_jsx("planeGeometry", { args: [layout.totalWidth + 0.1, layout.maxRows * layout.tagHeight + 0.1] }), _jsx("meshBasicMaterial", { color: 0x000000, opacity: 0.6, transparent: true, side: DoubleSide })] }), activeColumns.map(([columnIndex, columnTags], activeColIndex) => {
|
|
57
|
+
const xPos = (activeColIndex - (activeColumns.length - 1) / 2) * layout.columnSpacing;
|
|
58
|
+
return columnTags.map((tag, rowIndex) => {
|
|
59
|
+
const yOffset = -rowIndex * (layout.tagHeight + layout.tagSpacing);
|
|
60
|
+
return (_jsx(TagChip, { tag: tag, width: layout.tagWidth, height: layout.tagHeight, fontSize: 0.08, position: [xPos, yOffset, 0], doubleSided: true }, `${columnIndex}-${tag.id}`));
|
|
61
|
+
});
|
|
62
|
+
})] }) }) }));
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/components/TagBoard/components/TagDisplay/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Tag } from "../../types";
|
|
2
|
+
export interface TagDisplayLayout {
|
|
3
|
+
tagHeight: number;
|
|
4
|
+
tagWidth: number;
|
|
5
|
+
tagSpacing: number;
|
|
6
|
+
columnSpacing: number;
|
|
7
|
+
maxRows: number;
|
|
8
|
+
totalWidth: number;
|
|
9
|
+
}
|
|
10
|
+
export type ActiveColumn = [number, Tag[]];
|
|
11
|
+
/**
|
|
12
|
+
* 選択されたタグIDから実際のタグオブジェクトを取得
|
|
13
|
+
*/
|
|
14
|
+
export declare const getSelectedTags: (selectedTagIds: string[], flatTags: Tag[]) => Tag[];
|
|
15
|
+
/**
|
|
16
|
+
* 選択済みタグを列ごとにマッピングしてソート
|
|
17
|
+
*/
|
|
18
|
+
export declare const groupTagsByColumn: (selectedTags: Tag[], tags: Tag[][]) => ActiveColumn[];
|
|
19
|
+
/**
|
|
20
|
+
* レイアウト計算
|
|
21
|
+
*/
|
|
22
|
+
export declare const calculateLayout: (activeColumns: ActiveColumn[]) => TagDisplayLayout;
|
|
23
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/components/TagBoard/components/TagDisplay/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,eAAe,GAC1B,gBAAgB,MAAM,EAAE,EACxB,UAAU,GAAG,EAAE,KACd,GAAG,EAKL,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC5B,cAAc,GAAG,EAAE,EACnB,MAAM,GAAG,EAAE,EAAE,KACZ,YAAY,EAoBd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,eAAe,YAAY,EAAE,KAAG,gBAmB/D,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 選択されたタグIDから実際のタグオブジェクトを取得
|
|
3
|
+
*/
|
|
4
|
+
export const getSelectedTags = (selectedTagIds, flatTags) => {
|
|
5
|
+
const uniqueTagIds = [...new Set(selectedTagIds)];
|
|
6
|
+
return uniqueTagIds
|
|
7
|
+
.map((id) => flatTags.find((tag) => tag.id === id))
|
|
8
|
+
.filter((tag) => tag !== undefined);
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* 選択済みタグを列ごとにマッピングしてソート
|
|
12
|
+
*/
|
|
13
|
+
export const groupTagsByColumn = (selectedTags, tags) => {
|
|
14
|
+
const columnMap = new Map();
|
|
15
|
+
selectedTags.forEach((tag) => {
|
|
16
|
+
let columnIndex = -1;
|
|
17
|
+
for (let i = 0; i < tags.length; i++) {
|
|
18
|
+
if (tags[i].some((t) => t.id === tag.id)) {
|
|
19
|
+
columnIndex = i;
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (columnIndex === -1)
|
|
24
|
+
return;
|
|
25
|
+
if (!columnMap.has(columnIndex)) {
|
|
26
|
+
columnMap.set(columnIndex, []);
|
|
27
|
+
}
|
|
28
|
+
columnMap.get(columnIndex).push(tag);
|
|
29
|
+
});
|
|
30
|
+
return Array.from(columnMap.entries()).sort((a, b) => a[0] - b[0]);
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* レイアウト計算
|
|
34
|
+
*/
|
|
35
|
+
export const calculateLayout = (activeColumns) => {
|
|
36
|
+
const tagHeight = 0.16;
|
|
37
|
+
const tagWidth = 0.8;
|
|
38
|
+
const tagSpacing = 0;
|
|
39
|
+
const columnSpacing = tagWidth;
|
|
40
|
+
const maxRows = activeColumns.length > 0
|
|
41
|
+
? Math.max(...activeColumns.map(([, t]) => t.length))
|
|
42
|
+
: 0;
|
|
43
|
+
const totalWidth = activeColumns.length * tagWidth;
|
|
44
|
+
return {
|
|
45
|
+
tagHeight,
|
|
46
|
+
tagWidth,
|
|
47
|
+
tagSpacing,
|
|
48
|
+
columnSpacing,
|
|
49
|
+
maxRows,
|
|
50
|
+
totalWidth,
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../../src/components/TagBoard/components/TagDisplay/utils.ts"],"names":[],"mappings":"AAaA;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,cAAwB,EACxB,QAAe,EACR,EAAE;IACT,MAAM,YAAY,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC;IAClD,OAAO,YAAY;SAChB,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;SAClD,MAAM,CAAC,CAAC,GAAG,EAAc,EAAE,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC;AACpD,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,YAAmB,EACnB,IAAa,EACG,EAAE;IAClB,MAAM,SAAS,GAAG,IAAI,GAAG,EAAiB,CAAC;IAE3C,YAAY,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QAC3B,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBACzC,WAAW,GAAG,CAAC,CAAC;gBAChB,MAAM;YACR,CAAC;QACH,CAAC;QACD,IAAI,WAAW,KAAK,CAAC,CAAC;YAAE,OAAO;QAE/B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YAChC,SAAS,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACjC,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,aAA6B,EAAoB,EAAE;IACjF,MAAM,SAAS,GAAG,IAAI,CAAC;IACvB,MAAM,QAAQ,GAAG,GAAG,CAAC;IACrB,MAAM,UAAU,GAAG,CAAC,CAAC;IACrB,MAAM,aAAa,GAAG,QAAQ,CAAC;IAE/B,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC;QACtC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC,CAAC;IACN,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,GAAG,QAAQ,CAAC;IAEnD,OAAO;QACL,SAAS;QACT,QAAQ;QACR,UAAU;QACV,aAAa;QACb,OAAO;QACP,UAAU;KACX,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface ActionButtonProps {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
color: number;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
scale: number;
|
|
8
|
+
position: [number, number, number];
|
|
9
|
+
onInteract: () => void;
|
|
10
|
+
interactionText: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const ActionButton: ({ id, label, color, width, height, scale, position, onInteract, interactionText, }: ActionButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
//# sourceMappingURL=ActionButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ActionButton.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TagBoard/components/TagSelector/components/ActionButton.tsx"],"names":[],"mappings":"AASA,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,YAAY,GAAI,oFAU1B,iBAAiB,4CAoBnB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* ActionButton コンポーネント
|
|
4
|
+
*
|
|
5
|
+
* TagSelector内で使用する汎用アクションボタン。
|
|
6
|
+
*/
|
|
7
|
+
import { Text } from "@react-three/drei";
|
|
8
|
+
import { Interactable } from "../../../../Interactable";
|
|
9
|
+
export const ActionButton = ({ id, label, color, width, height, scale, position, onInteract, interactionText, }) => {
|
|
10
|
+
return (_jsxs("group", { position: position, children: [_jsx(Interactable, { id: id, onInteract: onInteract, interactionText: interactionText, children: _jsxs("mesh", { children: [_jsx("boxGeometry", { args: [width, height, 0.01 * scale] }), _jsx("meshStandardMaterial", { color: color, opacity: 1, transparent: true })] }) }), _jsx(Text, { position: [0, 0, 0.006 * scale], fontSize: 0.15 * scale, color: 0xffffff, anchorX: "center", anchorY: "middle", children: label })] }));
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=ActionButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ActionButton.js","sourceRoot":"","sources":["../../../../../../src/components/TagBoard/components/TagSelector/components/ActionButton.tsx"],"names":[],"mappings":";AAAA;;;;GAIG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAcxD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,EAC3B,EAAE,EACF,KAAK,EACL,KAAK,EACL,KAAK,EACL,MAAM,EACN,KAAK,EACL,QAAQ,EACR,UAAU,EACV,eAAe,GACG,EAAE,EAAE;IACtB,OAAO,CACL,iBAAO,QAAQ,EAAE,QAAQ,aACvB,KAAC,YAAY,IAAC,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,YAC5E,2BACE,sBAAa,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAG,KAAK,CAAC,GAAI,EACpD,+BAAsB,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,WAAW,SAAG,IACzD,GACM,EACf,KAAC,IAAI,IACH,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,EAC/B,QAAQ,EAAE,IAAI,GAAG,KAAK,EACtB,KAAK,EAAE,QAAQ,EACf,OAAO,EAAC,QAAQ,EAChB,OAAO,EAAC,QAAQ,YAEf,KAAK,GACD,IACD,CACT,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Tag } from "../../../types";
|
|
2
|
+
export interface TagButtonProps {
|
|
3
|
+
tag: Tag;
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
scale: number;
|
|
7
|
+
position: [number, number, number];
|
|
8
|
+
isSelected: boolean;
|
|
9
|
+
onInteract: () => void;
|
|
10
|
+
}
|
|
11
|
+
export declare const TagButton: ({ tag, width, height, scale, position, isSelected, onInteract, }: TagButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=TagButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TagButton.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TagBoard/components/TagSelector/components/TagButton.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAE1C,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,GAAG,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,eAAO,MAAM,SAAS,GAAI,kEAQvB,cAAc,4CAwBhB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* TagButton コンポーネント
|
|
4
|
+
*
|
|
5
|
+
* タグ選択ボタン。選択状態のチェックマーク表示を含む。
|
|
6
|
+
*/
|
|
7
|
+
import { Text } from "@react-three/drei";
|
|
8
|
+
import { Interactable } from "../../../../Interactable";
|
|
9
|
+
import { TagChip } from "../../TagChip";
|
|
10
|
+
export const TagButton = ({ tag, width, height, scale, position, isSelected, onInteract, }) => {
|
|
11
|
+
return (_jsxs("group", { position: position, children: [_jsx(Interactable, { id: `tag-button-${tag.id}`, onInteract: onInteract, interactionText: tag.label, children: _jsx(TagChip, { tag: tag, width: width, height: height, fontSize: 0.15 * scale }) }), isSelected && (_jsx(Text, { position: [-0.58 * scale, -0.02 * scale, 0.012 * scale], fontSize: 0.2 * scale, color: tag.color, anchorX: "center", anchorY: "middle", children: "\u2713" }))] }));
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=TagButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TagButton.js","sourceRoot":"","sources":["../../../../../../src/components/TagBoard/components/TagSelector/components/TagButton.tsx"],"names":[],"mappings":";AAAA;;;;GAIG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAaxC,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,EACxB,GAAG,EACH,KAAK,EACL,MAAM,EACN,KAAK,EACL,QAAQ,EACR,UAAU,EACV,UAAU,GACK,EAAE,EAAE;IACnB,OAAO,CACL,iBAAO,QAAQ,EAAE,QAAQ,aACvB,KAAC,YAAY,IACX,EAAE,EAAE,cAAc,GAAG,CAAC,EAAE,EAAE,EAC1B,UAAU,EAAE,UAAU,EACtB,eAAe,EAAE,GAAG,CAAC,KAAK,YAE1B,KAAC,OAAO,IAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,GAAG,KAAK,GAAI,GAC9D,EAEd,UAAU,IAAI,CACb,KAAC,IAAI,IACH,QAAQ,EAAE,CAAC,CAAC,IAAI,GAAG,KAAK,EAAE,CAAC,IAAI,GAAG,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC,EACvD,QAAQ,EAAE,GAAG,GAAG,KAAK,EACrB,KAAK,EAAE,GAAG,CAAC,KAAK,EAChB,OAAO,EAAC,QAAQ,EAChB,OAAO,EAAC,QAAQ,uBAGX,CACR,IACK,CACT,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type TagSelectorProps } from "../../types";
|
|
2
|
+
export declare const TagSelector: ({ tags, title, instanceStateKey, position, rotation, scale, tagsVisible, onTagsVisibleChange, }: TagSelectorProps) => import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/TagBoard/components/TagSelector/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAKpD,eAAO,MAAM,WAAW,GAAI,iGASzB,gBAAgB,4CAyGlB,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* TagSelector コンポーネント
|
|
4
|
+
*
|
|
5
|
+
* タグ選択用のボードUIを表示し、選択状態をインスタンス状態(`useInstanceState`)へ反映します。
|
|
6
|
+
* 可視状態のトグルも提供します。
|
|
7
|
+
*
|
|
8
|
+
* Props 概要:
|
|
9
|
+
* - tags: 表示・選択対象のタグ一覧
|
|
10
|
+
* - title: ボード上部に表示するタイトル文言
|
|
11
|
+
* - instanceStateKey: 複数ボード設置時のキー識別子
|
|
12
|
+
* - position/rotation/scale: ボードの位置・回転・スケール
|
|
13
|
+
* - tagsVisible: タグ表示/非表示の状態
|
|
14
|
+
* - onTagsVisibleChange: タグ表示/非表示の変更コールバック
|
|
15
|
+
*/
|
|
16
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
17
|
+
import { Text } from "@react-three/drei";
|
|
18
|
+
import { useUsers } from "../../../../contexts/UsersContext";
|
|
19
|
+
import { useInstanceState } from "../../../../hooks/useInstanceState";
|
|
20
|
+
import { ActionButton } from "./components/ActionButton";
|
|
21
|
+
import { TagButton } from "./components/TagButton";
|
|
22
|
+
import { calculateLayout, toggleTagSelection } from "./utils";
|
|
23
|
+
export const TagSelector = ({ tags, title, instanceStateKey, position, rotation, scale, tagsVisible, onTagsVisibleChange, }) => {
|
|
24
|
+
const { localUser } = useUsers();
|
|
25
|
+
const stateKey = `tag-${instanceStateKey}-${localUser?.id}`;
|
|
26
|
+
// グローバル同期用の選択タグID(他ユーザーからも見える状態に反映)
|
|
27
|
+
const [, setGlobalSelectedTagIds] = useInstanceState(stateKey, []);
|
|
28
|
+
const [localSelectedTagIds, setLocalSelectedTagIds] = useState([]);
|
|
29
|
+
// useMemo
|
|
30
|
+
const flatTags = useMemo(() => tags.flat(), [tags]);
|
|
31
|
+
const layout = useMemo(() => calculateLayout(tags, scale), [tags, scale]);
|
|
32
|
+
// localSelectedTagIds が変更されたらグローバル状態に同期
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (!localUser?.id)
|
|
35
|
+
return;
|
|
36
|
+
setGlobalSelectedTagIds(localSelectedTagIds);
|
|
37
|
+
}, [localSelectedTagIds, localUser?.id, setGlobalSelectedTagIds]);
|
|
38
|
+
// useCallback
|
|
39
|
+
const handleTagClick = useCallback((tagId) => {
|
|
40
|
+
setLocalSelectedTagIds((prev) => toggleTagSelection(prev, tagId, flatTags));
|
|
41
|
+
}, [flatTags]);
|
|
42
|
+
const handleClear = useCallback(() => {
|
|
43
|
+
setLocalSelectedTagIds([]);
|
|
44
|
+
}, []);
|
|
45
|
+
const handleToggleVisibility = useCallback(() => {
|
|
46
|
+
onTagsVisibleChange(!tagsVisible);
|
|
47
|
+
}, [onTagsVisibleChange, tagsVisible]);
|
|
48
|
+
return (_jsxs("group", { position: position, rotation: rotation, children: [_jsxs("mesh", { position: [0, 0, -0.02], children: [_jsx("planeGeometry", { args: [layout.boardWidth, layout.boardHeight] }), _jsx("meshBasicMaterial", { color: 0x2a2a2a })] }), _jsx(Text, { position: [0, layout.titleY, 0], fontSize: 0.2 * scale, color: "white", anchorX: "center", anchorY: "middle", fontWeight: "bold", children: title }), _jsx(ActionButton, { id: "tag-clear-button", label: "\u5168\u524A\u9664", color: 0xff6666, width: layout.buttonWidth, height: 0.35 * scale, scale: scale, position: [layout.buttonLeftX, layout.buttonGroupY - 0.3 * scale, -0.01], onInteract: handleClear, interactionText: "\u9078\u629E\u3092\u30AF\u30EA\u30A2" }), _jsx(ActionButton, { id: "tag-visibility-toggle", label: tagsVisible ? "非表示" : "表示", color: tagsVisible ? 0x00aa00 : 0xaa0000, width: layout.buttonWidth, height: 0.35 * scale, scale: scale, position: [layout.buttonRightX, layout.buttonGroupY - 0.3 * scale, -0.01], onInteract: handleToggleVisibility, interactionText: tagsVisible ? "タグを非表示" : "タグを表示" }), tags.map((columnTags, colIndex) => {
|
|
49
|
+
const xPos = (colIndex - (layout.columns - 1) / 2) * layout.columnSpacing;
|
|
50
|
+
return columnTags.map((tag, rowIndex) => {
|
|
51
|
+
const yPos = layout.tagStartY - rowIndex * layout.tagHeight;
|
|
52
|
+
const isSelected = localSelectedTagIds.includes(tag.id);
|
|
53
|
+
return (_jsx(TagButton, { tag: tag, width: layout.tagWidth, height: layout.tagHeight, scale: scale, position: [xPos, yPos, -0.01], isSelected: isSelected, onInteract: () => handleTagClick(tag.id) }, tag.id));
|
|
54
|
+
});
|
|
55
|
+
})] }));
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/components/TagBoard/components/TagSelector/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type Tag } from "../../types";
|
|
2
|
+
export interface TagSelectorLayout {
|
|
3
|
+
tagHeight: number;
|
|
4
|
+
tagWidth: number;
|
|
5
|
+
columnSpacing: number;
|
|
6
|
+
columns: number;
|
|
7
|
+
boardWidth: number;
|
|
8
|
+
boardHeight: number;
|
|
9
|
+
titleY: number;
|
|
10
|
+
buttonGroupY: number;
|
|
11
|
+
tagStartY: number;
|
|
12
|
+
buttonWidth: number;
|
|
13
|
+
buttonLeftX: number;
|
|
14
|
+
buttonRightX: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* タグIDの選択状態をトグルし、tagsの順番でソートして返す
|
|
18
|
+
*/
|
|
19
|
+
export declare const toggleTagSelection: (prevIds: string[], tagId: string, flatTags: Tag[]) => string[];
|
|
20
|
+
export declare const calculateLayout: (tags: Tag[][], scale: number) => TagSelectorLayout;
|
|
21
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/components/TagBoard/components/TagSelector/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,SAAS,MAAM,EAAE,EACjB,OAAO,MAAM,EACb,UAAU,GAAG,EAAE,KACd,MAAM,EAaR,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,MAAM,GAAG,EAAE,EAAE,EAAE,OAAO,MAAM,KAAG,iBAmC9D,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* タグIDの選択状態をトグルし、tagsの順番でソートして返す
|
|
3
|
+
*/
|
|
4
|
+
export const toggleTagSelection = (prevIds, tagId, flatTags) => {
|
|
5
|
+
let newIds;
|
|
6
|
+
if (prevIds.includes(tagId)) {
|
|
7
|
+
newIds = prevIds.filter((id) => id !== tagId);
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
newIds = [...new Set([...prevIds, tagId])];
|
|
11
|
+
}
|
|
12
|
+
// tags配列の順番に合わせてソート
|
|
13
|
+
return newIds.sort((a, b) => {
|
|
14
|
+
const indexA = flatTags.findIndex((tag) => tag.id === a);
|
|
15
|
+
const indexB = flatTags.findIndex((tag) => tag.id === b);
|
|
16
|
+
return indexA - indexB;
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
export const calculateLayout = (tags, scale) => {
|
|
20
|
+
const tagHeight = 0.27 * scale;
|
|
21
|
+
const tagWidth = 1.33 * scale;
|
|
22
|
+
const columnSpacing = tagWidth;
|
|
23
|
+
const columns = tags.length;
|
|
24
|
+
const maxRowsInColumn = Math.max(...tags.map((col) => col.length), 0);
|
|
25
|
+
const boardWidth = columns * tagWidth + 0.2 * scale;
|
|
26
|
+
const headerHeight = 1.0 * scale;
|
|
27
|
+
const boardHeight = maxRowsInColumn * tagHeight + headerHeight;
|
|
28
|
+
const boardTop = boardHeight / 2;
|
|
29
|
+
const titleY = boardTop - 0.25 * scale;
|
|
30
|
+
const buttonGroupY = boardTop - 0.3 * scale;
|
|
31
|
+
const tagStartY = boardTop - headerHeight;
|
|
32
|
+
const buttonWidth = boardWidth / 2 - 0.05 * scale;
|
|
33
|
+
const buttonLeftX = -boardWidth / 4;
|
|
34
|
+
const buttonRightX = boardWidth / 4;
|
|
35
|
+
return {
|
|
36
|
+
tagHeight,
|
|
37
|
+
tagWidth,
|
|
38
|
+
columnSpacing,
|
|
39
|
+
columns,
|
|
40
|
+
boardWidth,
|
|
41
|
+
boardHeight,
|
|
42
|
+
titleY,
|
|
43
|
+
buttonGroupY,
|
|
44
|
+
tagStartY,
|
|
45
|
+
buttonWidth,
|
|
46
|
+
buttonLeftX,
|
|
47
|
+
buttonRightX,
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../../src/components/TagBoard/components/TagSelector/utils.ts"],"names":[],"mappings":"AAiBA;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,OAAiB,EACjB,KAAa,EACb,QAAe,EACL,EAAE;IACZ,IAAI,MAAgB,CAAC;IACrB,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC;IAChD,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;IACD,oBAAoB;IACpB,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC1B,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QACzD,OAAO,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAAa,EAAE,KAAa,EAAqB,EAAE;IACjF,MAAM,SAAS,GAAG,IAAI,GAAG,KAAK,CAAC;IAC/B,MAAM,QAAQ,GAAG,IAAI,GAAG,KAAK,CAAC;IAC9B,MAAM,aAAa,GAAG,QAAQ,CAAC;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC;IAE5B,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IACtE,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,GAAG,GAAG,KAAK,CAAC;IAEpD,MAAM,YAAY,GAAG,GAAG,GAAG,KAAK,CAAC;IACjC,MAAM,WAAW,GAAG,eAAe,GAAG,SAAS,GAAG,YAAY,CAAC;IAE/D,MAAM,QAAQ,GAAG,WAAW,GAAG,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,QAAQ,GAAG,IAAI,GAAG,KAAK,CAAC;IACvC,MAAM,YAAY,GAAG,QAAQ,GAAG,GAAG,GAAG,KAAK,CAAC;IAC5C,MAAM,SAAS,GAAG,QAAQ,GAAG,YAAY,CAAC;IAE1C,MAAM,WAAW,GAAG,UAAU,GAAG,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC;IAClD,MAAM,WAAW,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC;IACpC,MAAM,YAAY,GAAG,UAAU,GAAG,CAAC,CAAC;IAEpC,OAAO;QACL,SAAS;QACT,QAAQ;QACR,aAAa;QACb,OAAO;QACP,UAAU;QACV,WAAW;QACX,MAAM;QACN,YAAY;QACZ,SAAS;QACT,WAAW;QACX,WAAW;QACX,YAAY;KACb,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/components/TagBoard/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,SAAS,CAAC;AAEnC,eAAO,MAAM,aAAa,6BAAS,CAAC;AACpC,eAAO,MAAM,eAAe,IAAI,CAAC;AAEjC,eAAO,MAAM,YAAY,EAAE,GAAG,EAW7B,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const DEFAULT_TITLE = "タグ選択";
|
|
2
|
+
export const DEFAULT_COLUMNS = 3;
|
|
3
|
+
export const DEFAULT_TAGS = [
|
|
4
|
+
{ color: "#2ECC71", id: "want-talk", label: "話したい" },
|
|
5
|
+
{ color: "#3498DB", id: "want-listen", label: "聞きたい" },
|
|
6
|
+
{ color: "#95A5A6", id: "silent", label: "無言" },
|
|
7
|
+
{ color: "#1ABC9C", id: "developer", label: "開発者" },
|
|
8
|
+
{ color: "#2980B9", id: "student", label: "学生" },
|
|
9
|
+
{ color: "#F1C40F", id: "beginner", label: "初心者" },
|
|
10
|
+
{ color: "#9B59B6", id: "dont-know", label: "なんもわからん" },
|
|
11
|
+
{ color: "#8BC34A", id: "working", label: "作業中" },
|
|
12
|
+
{ color: "#BF7B41", id: "away", label: "離席中" },
|
|
13
|
+
{ color: "#FF9800", id: "cat", label: "ねこ" },
|
|
14
|
+
];
|
|
15
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/components/TagBoard/constants.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC;AACpC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AAEjC,MAAM,CAAC,MAAM,YAAY,GAAU;IACjC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE;IACpD,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE;IACtD,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE;IAC/C,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE;IACnD,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE;IAChD,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE;IAClD,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE;IACvD,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE;IACjD,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE;IAC9C,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE;CAC7C,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type TagBoardProps } from "./types";
|
|
2
|
+
export { type TagBoardProps, type Tag } from "./types";
|
|
3
|
+
export declare const TagBoard: ({ tags, columns, title, instanceStateKey, position, rotation, scale, }: TagBoardProps) => import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/TagBoard/index.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAG7C,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,GAAG,EAAE,MAAM,SAAS,CAAC;AAEvD,eAAO,MAAM,QAAQ,GAAI,wEAQtB,aAAa,4CA+Cf,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* TagBoard コンポーネント
|
|
4
|
+
*
|
|
5
|
+
* ユーザーが選択したタグをローカル/グローバルに扱い、
|
|
6
|
+
* ボードUI(`TagSelector`)と、各ユーザー頭上へのタグ表示(`TagDisplay`)を提供します。
|
|
7
|
+
*
|
|
8
|
+
* 役割:
|
|
9
|
+
* - TagSelector: タグ選択ボードUI の提供
|
|
10
|
+
* - TagDisplay: 各ユーザー頭上へのタグ表示
|
|
11
|
+
* - 両者の同期: インスタンス状態を通じた連携
|
|
12
|
+
*/
|
|
13
|
+
import { useMemo, useState } from "react";
|
|
14
|
+
import { useUsers } from "../../contexts/UsersContext";
|
|
15
|
+
import { TagSelector } from "./components/TagSelector";
|
|
16
|
+
import { TagDisplay } from "./components/TagDisplay";
|
|
17
|
+
import { DEFAULT_COLUMNS, DEFAULT_TAGS, DEFAULT_TITLE } from "./constants";
|
|
18
|
+
import { splitIntoColumns } from "./utils";
|
|
19
|
+
export const TagBoard = ({ tags = DEFAULT_TAGS, columns = DEFAULT_COLUMNS, title = DEFAULT_TITLE, instanceStateKey, position = [0, 0, 0], rotation = [0, 0, 0], scale = 1, }) => {
|
|
20
|
+
const { remoteUsers, getMovement, getLocalMovement, localUser } = useUsers();
|
|
21
|
+
const [tagsVisible, setTagsVisible] = useState(true);
|
|
22
|
+
const tagColumns = useMemo(() => splitIntoColumns(tags, columns), [tags, columns]);
|
|
23
|
+
return (_jsxs(_Fragment, { children: [_jsx(TagSelector, { tags: tagColumns, title: title, instanceStateKey: instanceStateKey, position: position, rotation: rotation, scale: scale, tagsVisible: tagsVisible, onTagsVisibleChange: setTagsVisible }), localUser && (_jsx(TagDisplay, { userId: localUser.id, getMovement: getLocalMovement, tags: tagColumns, visible: tagsVisible, instanceStateKey: instanceStateKey })), remoteUsers.map((user) => (_jsx(TagDisplay, { userId: user.id, getMovement: getMovement, tags: tagColumns, visible: tagsVisible, instanceStateKey: instanceStateKey }, user.id)))] }));
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/TagBoard/index.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAI3C,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,EACvB,IAAI,GAAG,YAAY,EACnB,OAAO,GAAG,eAAe,EACzB,KAAK,GAAG,aAAa,EACrB,gBAAgB,EAChB,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EACpB,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EACpB,KAAK,GAAG,CAAC,GACK,EAAE,EAAE;IAClB,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC7E,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAErD,MAAM,UAAU,GAAG,OAAO,CACxB,GAAG,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,EACrC,CAAC,IAAI,EAAE,OAAO,CAAC,CAChB,CAAC;IAEF,OAAO,CACL,8BAEE,KAAC,WAAW,IACV,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,KAAK,EACZ,gBAAgB,EAAE,gBAAgB,EAClC,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,WAAW,EACxB,mBAAmB,EAAE,cAAc,GACnC,EAGD,SAAS,IAAI,CACZ,KAAC,UAAU,IACT,MAAM,EAAE,SAAS,CAAC,EAAE,EACpB,WAAW,EAAE,gBAAgB,EAC7B,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,WAAW,EACpB,gBAAgB,EAAE,gBAAgB,GAClC,CACH,EAGA,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACzB,KAAC,UAAU,IAET,MAAM,EAAE,IAAI,CAAC,EAAE,EACf,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,WAAW,EACpB,gBAAgB,EAAE,gBAAgB,IAL7B,IAAI,CAAC,EAAE,CAMZ,CACH,CAAC,IACD,CACJ,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type PlayerMovement } from "../../types/movement";
|
|
2
|
+
/** 表示用のタグ定義 */
|
|
3
|
+
export interface Tag {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
color: string;
|
|
7
|
+
}
|
|
8
|
+
/** TagBoard のプロパティ */
|
|
9
|
+
export interface TagBoardProps {
|
|
10
|
+
/** 表示・選択対象のタグ(省略時はデフォルトを使用) */
|
|
11
|
+
tags?: Tag[];
|
|
12
|
+
/** 表示列数(省略時は3列) */
|
|
13
|
+
columns?: number;
|
|
14
|
+
/** タイトル文言 */
|
|
15
|
+
title?: string;
|
|
16
|
+
/** インスタンス状態のキー(複数ボード設置時の識別用) */
|
|
17
|
+
instanceStateKey: string;
|
|
18
|
+
/** ボードの位置 */
|
|
19
|
+
position?: [number, number, number];
|
|
20
|
+
/** ボードの回転 */
|
|
21
|
+
rotation?: [number, number, number];
|
|
22
|
+
/** 全体スケール */
|
|
23
|
+
scale?: number;
|
|
24
|
+
}
|
|
25
|
+
/** TagDisplay のプロパティ */
|
|
26
|
+
export interface TagDisplayProps {
|
|
27
|
+
userId: string;
|
|
28
|
+
getMovement: (userId: string) => PlayerMovement | undefined;
|
|
29
|
+
tags: Tag[][];
|
|
30
|
+
visible: boolean;
|
|
31
|
+
instanceStateKey: string;
|
|
32
|
+
}
|
|
33
|
+
/** TagSelector のプロパティ */
|
|
34
|
+
export interface TagSelectorProps {
|
|
35
|
+
tags: Tag[][];
|
|
36
|
+
title: string;
|
|
37
|
+
instanceStateKey: string;
|
|
38
|
+
position: [number, number, number];
|
|
39
|
+
rotation: [number, number, number];
|
|
40
|
+
scale: number;
|
|
41
|
+
/** タグ表示/非表示の状態 */
|
|
42
|
+
tagsVisible: boolean;
|
|
43
|
+
/** タグ表示/非表示の変更コールバック */
|
|
44
|
+
onTagsVisibleChange: (visible: boolean) => void;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/TagBoard/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,eAAe;AACf,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,sBAAsB;AACtB,MAAM,WAAW,aAAa;IAC5B,+BAA+B;IAC/B,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACb,mBAAmB;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa;IACb,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,aAAa;IACb,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,aAAa;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAwB;AACxB,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,cAAc,GAAG,SAAS,CAAC;IAC5D,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,yBAAyB;AACzB,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,wBAAwB;IACxB,mBAAmB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACjD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/components/TagBoard/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/components/TagBoard/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,SAAS,CAAC;AAEnC;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,GAAG,EAAE,EAAE,SAAS,MAAM,KAAG,GAAG,EAAE,EAgBpE,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* タグ配列を指定列数で分割する
|
|
3
|
+
* 各列にできるだけ均等にタグを配置する
|
|
4
|
+
*/
|
|
5
|
+
export const splitIntoColumns = (tags, columns) => {
|
|
6
|
+
if (columns <= 0 || tags.length === 0)
|
|
7
|
+
return [];
|
|
8
|
+
const result = Array.from({ length: columns }, () => []);
|
|
9
|
+
const baseCount = Math.floor(tags.length / columns);
|
|
10
|
+
const remainder = tags.length % columns;
|
|
11
|
+
let index = 0;
|
|
12
|
+
for (let col = 0; col < columns; col++) {
|
|
13
|
+
const count = baseCount + (col < remainder ? 1 : 0);
|
|
14
|
+
for (let i = 0; i < count; i++) {
|
|
15
|
+
result[col].push(tags[index++]);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=utils.js.map
|