@jkwd/inbase 0.1.21 → 0.1.22
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/README.md +13 -7
- package/apps/explorer/package.json +1 -0
- package/apps/explorer/scripts/explain-store.d.ts +135 -0
- package/apps/explorer/scripts/explain-store.mjs +666 -0
- package/apps/explorer/scripts/patch-lib.mjs +4 -0
- package/apps/explorer/scripts/scan-target.mjs +22 -5
- package/apps/explorer/scripts/session-store.d.ts +86 -11
- package/apps/explorer/scripts/session-store.mjs +371 -58
- package/apps/explorer/scripts/target-config.d.ts +38 -3
- package/apps/explorer/scripts/target-config.mjs +147 -3
- package/apps/explorer/src/App.tsx +1073 -158
- package/apps/explorer/src/agentIntent.ts +61 -7
- package/apps/explorer/src/codebase.ts +1 -1
- package/apps/explorer/src/devTargets.ts +66 -0
- package/apps/explorer/src/explain.ts +312 -0
- package/apps/explorer/src/index.css +874 -222
- package/apps/explorer/src/layout.ts +55 -0
- package/apps/explorer/src/scene/DistantFileBlocks.tsx +4 -2
- package/apps/explorer/src/scene/FileBlock.tsx +95 -72
- package/apps/explorer/src/scene/FolderArea.tsx +55 -32
- package/apps/explorer/src/scene/MapView.tsx +506 -33
- package/apps/explorer/src/scene/RelationLines.tsx +7 -0
- package/apps/explorer/src/scene/World.tsx +146 -32
- package/apps/explorer/src/speech.ts +228 -0
- package/apps/explorer/src/theme.ts +29 -0
- package/apps/explorer/src/types.ts +98 -8
- package/apps/explorer/src/ui/CanvasErrorBoundary.tsx +1 -1
- package/apps/explorer/src/ui/ExplainAskCard.tsx +142 -0
- package/apps/explorer/src/ui/ExplainHud.tsx +524 -0
- package/apps/explorer/src/ui/ExplainInfoPanel.tsx +135 -0
- package/apps/explorer/src/ui/ExplainPointer.tsx +73 -0
- package/apps/explorer/src/ui/EyeIcon.tsx +38 -1
- package/apps/explorer/src/ui/HUD.tsx +1067 -795
- package/apps/explorer/src/ui/NameInput.tsx +114 -5
- package/apps/explorer/src/userContext.ts +0 -11
- package/apps/explorer/src/userCreated.ts +54 -1
- package/apps/explorer/vite.config.ts +173 -26
- package/bin/inbase.mjs +11 -2
- package/bin/project.mjs +1 -1
- package/bin/session.mjs +287 -38
- package/package.json +4 -1
- package/skill/commands/amber.md +23 -0
- package/skill/commands/blue.md +13 -0
- package/skill/commands/coral.md +23 -0
- package/skill/commands/explain.md +77 -0
- package/skill/commands/green.md +23 -0
- package/skill/commands/inbase.md +7 -5
- package/skill/commands/lime.md +23 -0
- package/skill/commands/orange.md +23 -0
- package/skill/commands/purple.md +23 -0
- package/skill/commands/red.md +23 -0
- package/skill/commands/skipinbase.md +1 -1
- package/skill/commands/violet.md +23 -0
- package/skill/commands/yellow.md +23 -0
- package/skill/inbase/SKILL.md +124 -76
- package/apps/explorer/src/scene/BlockPlacer.tsx +0 -78
- package/apps/explorer/src/scene/IslandPlacer.tsx +0 -31
- package/apps/explorer/src/scene/SelectionThumbnail.tsx +0 -1069
|
@@ -572,6 +572,61 @@ export function worldBounds(layout: WorldLayout) {
|
|
|
572
572
|
}
|
|
573
573
|
}
|
|
574
574
|
|
|
575
|
+
export function regionBounds(
|
|
576
|
+
layout: WorldLayout,
|
|
577
|
+
fileIds: Iterable<string> = [],
|
|
578
|
+
folderPaths: Iterable<string> = [],
|
|
579
|
+
) {
|
|
580
|
+
let minX = Infinity
|
|
581
|
+
let maxX = -Infinity
|
|
582
|
+
let minZ = Infinity
|
|
583
|
+
let maxZ = -Infinity
|
|
584
|
+
let found = false
|
|
585
|
+
|
|
586
|
+
const include = (left: number, right: number, top: number, bottom: number) => {
|
|
587
|
+
found = true
|
|
588
|
+
minX = Math.min(minX, left)
|
|
589
|
+
maxX = Math.max(maxX, right)
|
|
590
|
+
minZ = Math.min(minZ, top)
|
|
591
|
+
maxZ = Math.max(maxZ, bottom)
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
for (const path of folderPaths) {
|
|
595
|
+
const folder = layout.folders[path]
|
|
596
|
+
if (!folder) continue
|
|
597
|
+
include(
|
|
598
|
+
folder.x - folder.width / 2,
|
|
599
|
+
folder.x + folder.width / 2,
|
|
600
|
+
folder.z,
|
|
601
|
+
folder.z + folder.depth,
|
|
602
|
+
)
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
for (const id of fileIds) {
|
|
606
|
+
const file = layout.files[id]
|
|
607
|
+
if (!file) continue
|
|
608
|
+
include(
|
|
609
|
+
file.position[0] - file.size[0] / 2,
|
|
610
|
+
file.position[0] + file.size[0] / 2,
|
|
611
|
+
file.position[2] - file.size[2] / 2,
|
|
612
|
+
file.position[2] + file.size[2] / 2,
|
|
613
|
+
)
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
if (!found) return worldBounds(layout)
|
|
617
|
+
|
|
618
|
+
return {
|
|
619
|
+
minX,
|
|
620
|
+
maxX,
|
|
621
|
+
minZ,
|
|
622
|
+
maxZ,
|
|
623
|
+
cx: (minX + maxX) / 2,
|
|
624
|
+
cz: (minZ + maxZ) / 2,
|
|
625
|
+
width: Math.max(maxX - minX, 8),
|
|
626
|
+
depth: Math.max(maxZ - minZ, 8),
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
575
630
|
export function fileChangeKind(
|
|
576
631
|
id: string,
|
|
577
632
|
planned: Set<string>,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useRef } from 'react'
|
|
2
2
|
import { Instances, Instance } from '@react-three/drei'
|
|
3
|
-
import { dimColor, fileColor } from '../theme'
|
|
3
|
+
import { dimColor, fileColor, blueprintPalette } from '../theme'
|
|
4
4
|
import type { FileNode, PlacedFile } from '../types'
|
|
5
5
|
|
|
6
6
|
type DistantFile = {
|
|
@@ -28,7 +28,9 @@ export function DistantFileBlocks({
|
|
|
28
28
|
<boxGeometry args={[1, 1, 1]} />
|
|
29
29
|
<meshLambertMaterial />
|
|
30
30
|
{items.map(({ file, placed, dimmed }) => {
|
|
31
|
-
const color = file.userCreated
|
|
31
|
+
const color = file.userCreated || file.colorHex
|
|
32
|
+
? blueprintPalette(file.colorHex).color
|
|
33
|
+
: fileColor(file.language)
|
|
32
34
|
return (
|
|
33
35
|
<Instance
|
|
34
36
|
key={file.id}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { memo, Suspense } from 'react'
|
|
2
2
|
import { Billboard, Edges, Html, Text } from '@react-three/drei'
|
|
3
|
-
import { CHANGE_HIGHLIGHT, CONFIG, dimColor, fileColor, FILE_SELECTION, MAP_SELECTION, type ChangeKind } from '../theme'
|
|
3
|
+
import { CHANGE_HIGHLIGHT, CONFIG, blueprintPalette, dimColor, fileColor, FILE_SELECTION, MAP_SELECTION, type ChangeKind } from '../theme'
|
|
4
4
|
import { NameInput } from '../ui/NameInput'
|
|
5
|
-
import {
|
|
5
|
+
import { BlueprintEyes } from '../ui/EyeIcon'
|
|
6
6
|
import { MapSelectBorder } from './MapSelectBorder'
|
|
7
7
|
import type { FileNode } from '../types'
|
|
8
8
|
import type { PlacedFile } from '../types'
|
|
@@ -26,12 +26,14 @@ type FileBlockProps = {
|
|
|
26
26
|
added?: boolean
|
|
27
27
|
aimed?: boolean
|
|
28
28
|
dimmed: boolean
|
|
29
|
+
focused?: boolean
|
|
29
30
|
naming?: boolean
|
|
30
31
|
mapMode?: boolean
|
|
31
32
|
highlightMapChange?: boolean
|
|
32
|
-
previewLabels?: boolean
|
|
33
33
|
labelVisible?: boolean
|
|
34
34
|
pointed?: boolean
|
|
35
|
+
pointedColors?: string[]
|
|
36
|
+
opacity?: number
|
|
35
37
|
onCommitName?: (name: string) => void
|
|
36
38
|
onCancelName?: () => void
|
|
37
39
|
}
|
|
@@ -90,32 +92,43 @@ export const FileBlock = memo(function FileBlock({
|
|
|
90
92
|
added = false,
|
|
91
93
|
aimed = false,
|
|
92
94
|
dimmed,
|
|
95
|
+
focused = false,
|
|
93
96
|
naming = false,
|
|
94
97
|
mapMode = false,
|
|
95
98
|
highlightMapChange = mapMode,
|
|
96
|
-
previewLabels = false,
|
|
97
99
|
labelVisible = true,
|
|
98
100
|
pointed = false,
|
|
101
|
+
pointedColors,
|
|
102
|
+
opacity = 1,
|
|
99
103
|
onCommitName,
|
|
100
104
|
onCancelName,
|
|
101
105
|
}: FileBlockProps) {
|
|
102
106
|
const [width, height, depth] = placed.size
|
|
103
107
|
const highlight =
|
|
104
|
-
changeKind && highlightMapChange && !selected
|
|
108
|
+
changeKind && highlightMapChange && !selected && !file.userCreated && !file.colorHex
|
|
105
109
|
? CHANGE_HIGHLIGHT[changeKind]
|
|
106
110
|
: null
|
|
107
111
|
const isAdded = added || Boolean(file.userCreated)
|
|
108
|
-
const
|
|
112
|
+
const tint = file.colorHex || file.userCreated ? blueprintPalette(file.colorHex) : null
|
|
113
|
+
const color = tint ? tint.color : isAdded ? '#7ec8e8' : fileColor(file.language)
|
|
109
114
|
const muted = dimColor(color, 0.32)
|
|
110
115
|
const label = fileLabel(file.name, changeKind, isAdded)
|
|
111
116
|
const mark = changeMark(changeKind, isAdded)
|
|
117
|
+
const eyeColors =
|
|
118
|
+
pointedColors && pointedColors.length > 0
|
|
119
|
+
? pointedColors
|
|
120
|
+
: pointed
|
|
121
|
+
? ['#f4f7fb']
|
|
122
|
+
: []
|
|
112
123
|
const labelColor = aimed
|
|
113
124
|
? '#9ad8ff'
|
|
114
125
|
: highlight
|
|
115
126
|
? highlight.color
|
|
116
|
-
:
|
|
117
|
-
?
|
|
118
|
-
:
|
|
127
|
+
: tint
|
|
128
|
+
? tint.label
|
|
129
|
+
: dimmed
|
|
130
|
+
? '#b4bcc8'
|
|
131
|
+
: '#e7ebf2'
|
|
119
132
|
const meshColor = aimed
|
|
120
133
|
? '#9ad8ff'
|
|
121
134
|
: highlight
|
|
@@ -135,10 +148,19 @@ export const FileBlock = memo(function FileBlock({
|
|
|
135
148
|
<mesh userData={{ fileId: file.id }} scale={[width, height, depth]}>
|
|
136
149
|
<boxGeometry args={[1, 1, 1]} />
|
|
137
150
|
{mapMode ? (
|
|
138
|
-
<meshBasicMaterial
|
|
151
|
+
<meshBasicMaterial
|
|
152
|
+
color={meshColor}
|
|
153
|
+
toneMapped={false}
|
|
154
|
+
transparent={opacity < 1}
|
|
155
|
+
opacity={opacity}
|
|
156
|
+
depthWrite={opacity >= 1}
|
|
157
|
+
/>
|
|
139
158
|
) : (
|
|
140
159
|
<meshLambertMaterial
|
|
141
160
|
color={meshColor}
|
|
161
|
+
transparent={opacity < 1}
|
|
162
|
+
opacity={opacity}
|
|
163
|
+
depthWrite={opacity >= 1}
|
|
142
164
|
emissive={
|
|
143
165
|
aimed
|
|
144
166
|
? '#3a6a80'
|
|
@@ -148,11 +170,13 @@ export const FileBlock = memo(function FileBlock({
|
|
|
148
170
|
? FILE_SELECTION.emissive
|
|
149
171
|
: related
|
|
150
172
|
? '#1f4a44'
|
|
151
|
-
:
|
|
152
|
-
?
|
|
153
|
-
:
|
|
154
|
-
?
|
|
155
|
-
:
|
|
173
|
+
: tint
|
|
174
|
+
? tint.emissive
|
|
175
|
+
: isAdded
|
|
176
|
+
? '#2a5064'
|
|
177
|
+
: dimmed
|
|
178
|
+
? muted
|
|
179
|
+
: color
|
|
156
180
|
}
|
|
157
181
|
emissiveIntensity={
|
|
158
182
|
aimed
|
|
@@ -191,31 +215,43 @@ export const FileBlock = memo(function FileBlock({
|
|
|
191
215
|
userData={{ fileId: file.id }}
|
|
192
216
|
/>
|
|
193
217
|
)}
|
|
218
|
+
{focused && mapMode && (
|
|
219
|
+
<MapSelectBorder
|
|
220
|
+
width={width}
|
|
221
|
+
depth={depth}
|
|
222
|
+
y={height / 2 + (selected ? 0.06 : 0.03)}
|
|
223
|
+
stroke={MAP_SELECTION.explainPad}
|
|
224
|
+
color={MAP_SELECTION.explain}
|
|
225
|
+
userData={{ fileId: file.id }}
|
|
226
|
+
/>
|
|
227
|
+
)}
|
|
194
228
|
{mapMode && !naming && mark && (
|
|
195
229
|
<MapChangeMark mark={mark} width={width} depth={depth} height={height} />
|
|
196
230
|
)}
|
|
197
|
-
{
|
|
231
|
+
{eyeColors.length > 0 && !naming && (
|
|
198
232
|
<Html
|
|
199
233
|
position={
|
|
200
234
|
mapMode
|
|
201
|
-
?
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
235
|
+
? [
|
|
236
|
+
width / 2 + Math.min(width, depth) * 0.28,
|
|
237
|
+
height / 2 + 0.04,
|
|
238
|
+
0,
|
|
239
|
+
]
|
|
240
|
+
: [
|
|
241
|
+
width * 0.38,
|
|
242
|
+
height / 2 + 0.18,
|
|
243
|
+
0,
|
|
244
|
+
]
|
|
205
245
|
}
|
|
206
246
|
center
|
|
247
|
+
distanceFactor={
|
|
248
|
+
mapMode ? Math.min(width, depth) / 24 : undefined
|
|
249
|
+
}
|
|
207
250
|
occlude={false}
|
|
208
251
|
style={{ pointerEvents: 'none' }}
|
|
209
252
|
zIndexRange={[40, 0]}
|
|
210
253
|
>
|
|
211
|
-
<
|
|
212
|
-
className="blueprint-eye"
|
|
213
|
-
data-map={mapMode ? 'true' : 'false'}
|
|
214
|
-
role="img"
|
|
215
|
-
aria-label="Keep in mind"
|
|
216
|
-
>
|
|
217
|
-
<EyeIcon size={mapMode ? 16 : 18} title="Keep in mind" />
|
|
218
|
-
</div>
|
|
254
|
+
<BlueprintEyes colors={eyeColors} mapMode={mapMode} />
|
|
219
255
|
</Html>
|
|
220
256
|
)}
|
|
221
257
|
{naming && onCommitName && onCancelName && (
|
|
@@ -236,6 +272,7 @@ export const FileBlock = memo(function FileBlock({
|
|
|
236
272
|
>
|
|
237
273
|
<NameInput
|
|
238
274
|
placeholder="File name"
|
|
275
|
+
fallbackName="New file"
|
|
239
276
|
onCommit={onCommitName}
|
|
240
277
|
onCancel={onCancelName}
|
|
241
278
|
/>
|
|
@@ -243,57 +280,43 @@ export const FileBlock = memo(function FileBlock({
|
|
|
243
280
|
)}
|
|
244
281
|
{showLabels && (
|
|
245
282
|
<Suspense fallback={null}>
|
|
246
|
-
{
|
|
247
|
-
<
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
283
|
+
<Billboard position={[0, height / 2 + (planned || highlight ? 0.55 : 0.38), 0]}>
|
|
284
|
+
<Text
|
|
285
|
+
fontSize={0.28}
|
|
286
|
+
color={labelColor}
|
|
287
|
+
anchorX="center"
|
|
288
|
+
anchorY="bottom"
|
|
289
|
+
maxWidth={3.4}
|
|
253
290
|
>
|
|
254
|
-
|
|
255
|
-
</
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
291
|
+
{label}
|
|
292
|
+
</Text>
|
|
293
|
+
</Billboard>
|
|
294
|
+
{height >= SIDE_LABEL_MIN_HEIGHT &&
|
|
295
|
+
SIDE_LABELS.map((side) => {
|
|
296
|
+
const face = side.axis === 'x' ? width : depth
|
|
297
|
+
const x =
|
|
298
|
+
side.axis === 'x' ? side.sign * (width / 2 + SIDE_LABEL_PAD) : 0
|
|
299
|
+
const z =
|
|
300
|
+
side.axis === 'z' ? side.sign * (depth / 2 + SIDE_LABEL_PAD) : 0
|
|
301
|
+
return (
|
|
259
302
|
<Text
|
|
260
|
-
|
|
303
|
+
key={`${side.axis}:${side.sign}`}
|
|
304
|
+
position={[x, -height / 2 + 0.22, z]}
|
|
305
|
+
rotation={[0, side.rotationY, 0]}
|
|
306
|
+
fontSize={0.22}
|
|
261
307
|
color={labelColor}
|
|
262
308
|
anchorX="center"
|
|
263
|
-
anchorY="
|
|
264
|
-
maxWidth={
|
|
309
|
+
anchorY="middle"
|
|
310
|
+
maxWidth={face - 0.2}
|
|
311
|
+
overflowWrap="break-word"
|
|
312
|
+
outlineWidth={0.012}
|
|
313
|
+
outlineColor="#11151c"
|
|
314
|
+
depthOffset={-1}
|
|
265
315
|
>
|
|
266
316
|
{label}
|
|
267
317
|
</Text>
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
SIDE_LABELS.map((side) => {
|
|
271
|
-
const face = side.axis === 'x' ? width : depth
|
|
272
|
-
const x =
|
|
273
|
-
side.axis === 'x' ? side.sign * (width / 2 + SIDE_LABEL_PAD) : 0
|
|
274
|
-
const z =
|
|
275
|
-
side.axis === 'z' ? side.sign * (depth / 2 + SIDE_LABEL_PAD) : 0
|
|
276
|
-
return (
|
|
277
|
-
<Text
|
|
278
|
-
key={`${side.axis}:${side.sign}`}
|
|
279
|
-
position={[x, -height / 2 + 0.22, z]}
|
|
280
|
-
rotation={[0, side.rotationY, 0]}
|
|
281
|
-
fontSize={0.22}
|
|
282
|
-
color={labelColor}
|
|
283
|
-
anchorX="center"
|
|
284
|
-
anchorY="middle"
|
|
285
|
-
maxWidth={face - 0.2}
|
|
286
|
-
overflowWrap="break-word"
|
|
287
|
-
outlineWidth={0.012}
|
|
288
|
-
outlineColor="#11151c"
|
|
289
|
-
depthOffset={-1}
|
|
290
|
-
>
|
|
291
|
-
{label}
|
|
292
|
-
</Text>
|
|
293
|
-
)
|
|
294
|
-
})}
|
|
295
|
-
</>
|
|
296
|
-
)}
|
|
318
|
+
)
|
|
319
|
+
})}
|
|
297
320
|
</Suspense>
|
|
298
321
|
)}
|
|
299
322
|
</group>
|
|
@@ -3,6 +3,7 @@ import { Html, Text } from '@react-three/drei'
|
|
|
3
3
|
import {
|
|
4
4
|
CHANGE_HIGHLIGHT,
|
|
5
5
|
CONFIG,
|
|
6
|
+
blueprintPalette,
|
|
6
7
|
folderAisleColor,
|
|
7
8
|
folderFloorColor,
|
|
8
9
|
MAP_SELECTION,
|
|
@@ -11,7 +12,7 @@ import {
|
|
|
11
12
|
import type { PlacedFolder } from '../types'
|
|
12
13
|
import { MapSelectBorder } from './MapSelectBorder'
|
|
13
14
|
import { NameInput } from '../ui/NameInput'
|
|
14
|
-
import {
|
|
15
|
+
import { BlueprintEyes } from '../ui/EyeIcon'
|
|
15
16
|
|
|
16
17
|
type FolderAreaProps = {
|
|
17
18
|
folder: PlacedFolder
|
|
@@ -19,9 +20,10 @@ type FolderAreaProps = {
|
|
|
19
20
|
selected?: boolean
|
|
20
21
|
mapMode?: boolean
|
|
21
22
|
highlightKind?: ChangeKind | null
|
|
22
|
-
previewLabels?: boolean
|
|
23
23
|
labelVisible?: boolean
|
|
24
24
|
pointed?: boolean
|
|
25
|
+
pointedColors?: string[]
|
|
26
|
+
opacity?: number
|
|
25
27
|
onCommitName?: (name: string) => void
|
|
26
28
|
onCancelName?: () => void
|
|
27
29
|
}
|
|
@@ -32,26 +34,35 @@ export function FolderArea({
|
|
|
32
34
|
selected = false,
|
|
33
35
|
mapMode = false,
|
|
34
36
|
highlightKind = null,
|
|
35
|
-
previewLabels = false,
|
|
36
37
|
labelVisible = true,
|
|
37
38
|
pointed = false,
|
|
39
|
+
pointedColors,
|
|
40
|
+
opacity = 1,
|
|
38
41
|
onCommitName,
|
|
39
42
|
onCancelName,
|
|
40
43
|
}: FolderAreaProps) {
|
|
41
44
|
const added = Boolean(folder.added)
|
|
42
45
|
const highlight = highlightKind ? CHANGE_HIGHLIGHT[highlightKind] : null
|
|
43
46
|
const addedOnly = added && !highlight
|
|
44
|
-
const
|
|
47
|
+
const tint = addedOnly ? blueprintPalette(folder.colorHex) : null
|
|
48
|
+
const outline = highlight ? highlight.color : addedOnly ? tint?.color ?? '#7ec8e8' : null
|
|
45
49
|
const color = highlight
|
|
46
50
|
? highlight.floor
|
|
47
51
|
: addedOnly
|
|
48
|
-
? '#16323f'
|
|
52
|
+
? tint?.floor ?? '#16323f'
|
|
49
53
|
: folderFloorColor(folder.path)
|
|
50
54
|
const aisle = highlight
|
|
51
55
|
? highlight.aisle
|
|
52
56
|
: addedOnly
|
|
53
|
-
? '#23485a'
|
|
57
|
+
? tint?.aisle ?? '#23485a'
|
|
54
58
|
: folderAisleColor(folder.path)
|
|
59
|
+
const eyeColors =
|
|
60
|
+
pointedColors && pointedColors.length > 0
|
|
61
|
+
? pointedColors
|
|
62
|
+
: pointed
|
|
63
|
+
? [MAP_SELECTION.pointed]
|
|
64
|
+
: []
|
|
65
|
+
const pointedColor = eyeColors[eyeColors.length - 1]
|
|
55
66
|
const label =
|
|
56
67
|
highlightKind === 'remove'
|
|
57
68
|
? `- ${folder.name}`
|
|
@@ -59,6 +70,13 @@ export function FolderArea({
|
|
|
59
70
|
? `+ ${folder.name}`
|
|
60
71
|
: folder.name
|
|
61
72
|
|
|
73
|
+
const faded = opacity < 1
|
|
74
|
+
const floorMaterial = {
|
|
75
|
+
transparent: faded,
|
|
76
|
+
opacity,
|
|
77
|
+
depthWrite: !faded,
|
|
78
|
+
}
|
|
79
|
+
|
|
62
80
|
return (
|
|
63
81
|
<group position={[folder.x, 0, folder.z + folder.depth / 2]}>
|
|
64
82
|
{outline && (
|
|
@@ -67,12 +85,18 @@ export function FolderArea({
|
|
|
67
85
|
<meshBasicMaterial
|
|
68
86
|
color={outline}
|
|
69
87
|
toneMapped={false}
|
|
88
|
+
{...floorMaterial}
|
|
70
89
|
/>
|
|
71
90
|
</mesh>
|
|
72
91
|
)}
|
|
73
92
|
<mesh rotation={[-Math.PI / 2, 0, 0]}>
|
|
74
93
|
<planeGeometry args={[folder.width, folder.depth]} />
|
|
75
|
-
<meshBasicMaterial
|
|
94
|
+
<meshBasicMaterial
|
|
95
|
+
color={color}
|
|
96
|
+
transparent={faded}
|
|
97
|
+
opacity={opacity}
|
|
98
|
+
depthWrite={!faded}
|
|
99
|
+
/>
|
|
76
100
|
</mesh>
|
|
77
101
|
{selected && mapMode && (
|
|
78
102
|
<MapSelectBorder
|
|
@@ -83,9 +107,18 @@ export function FolderArea({
|
|
|
83
107
|
color={MAP_SELECTION.island}
|
|
84
108
|
/>
|
|
85
109
|
)}
|
|
110
|
+
{eyeColors.length > 0 && !naming && (
|
|
111
|
+
<MapSelectBorder
|
|
112
|
+
width={folder.width}
|
|
113
|
+
depth={folder.depth}
|
|
114
|
+
y={selected && mapMode ? 0.09 : 0.05}
|
|
115
|
+
stroke={MAP_SELECTION.pointedPad}
|
|
116
|
+
color={pointedColor ?? MAP_SELECTION.pointed}
|
|
117
|
+
/>
|
|
118
|
+
)}
|
|
86
119
|
<mesh position={[0, 0.02, 0]} rotation={[-Math.PI / 2, 0, 0]}>
|
|
87
120
|
<planeGeometry args={[CONFIG.bridgeWidth, folder.depth]} />
|
|
88
|
-
<meshBasicMaterial color={aisle} />
|
|
121
|
+
<meshBasicMaterial color={aisle} {...floorMaterial} />
|
|
89
122
|
</mesh>
|
|
90
123
|
{folder.width > 28 && (
|
|
91
124
|
<mesh
|
|
@@ -93,25 +126,18 @@ export function FolderArea({
|
|
|
93
126
|
rotation={[-Math.PI / 2, 0, 0]}
|
|
94
127
|
>
|
|
95
128
|
<planeGeometry args={[folder.width, CONFIG.bridgeWidth]} />
|
|
96
|
-
<meshBasicMaterial color={aisle} />
|
|
129
|
+
<meshBasicMaterial color={aisle} {...floorMaterial} />
|
|
97
130
|
</mesh>
|
|
98
131
|
)}
|
|
99
|
-
{
|
|
132
|
+
{eyeColors.length > 0 && !naming && !mapMode && (
|
|
100
133
|
<Html
|
|
101
|
-
position={[
|
|
134
|
+
position={[1.45, 1.75, -folder.depth / 2 + 1.6]}
|
|
102
135
|
center
|
|
103
136
|
occlude={false}
|
|
104
137
|
style={{ pointerEvents: 'none' }}
|
|
105
138
|
zIndexRange={[40, 0]}
|
|
106
139
|
>
|
|
107
|
-
<
|
|
108
|
-
className="blueprint-eye"
|
|
109
|
-
data-map={mapMode ? 'true' : 'false'}
|
|
110
|
-
role="img"
|
|
111
|
-
aria-label="Keep in mind"
|
|
112
|
-
>
|
|
113
|
-
<EyeIcon size={mapMode ? 18 : 22} title="Keep in mind" />
|
|
114
|
-
</div>
|
|
140
|
+
<BlueprintEyes colors={eyeColors} size={20} />
|
|
115
141
|
</Html>
|
|
116
142
|
)}
|
|
117
143
|
{naming && mapMode && onCommitName && onCancelName && (
|
|
@@ -124,31 +150,28 @@ export function FolderArea({
|
|
|
124
150
|
>
|
|
125
151
|
<NameInput
|
|
126
152
|
placeholder="Folder name"
|
|
153
|
+
fallbackName="New folder"
|
|
127
154
|
onCommit={onCommitName}
|
|
128
155
|
onCancel={onCancelName}
|
|
129
156
|
/>
|
|
130
157
|
</Html>
|
|
131
158
|
)}
|
|
132
159
|
<Suspense fallback={null}>
|
|
133
|
-
{!naming &&
|
|
134
|
-
<Html
|
|
135
|
-
position={[0, 1.35, -folder.depth / 2 + 1.6]}
|
|
136
|
-
center
|
|
137
|
-
occlude={false}
|
|
138
|
-
style={{ pointerEvents: 'none' }}
|
|
139
|
-
zIndexRange={[20, 0]}
|
|
140
|
-
>
|
|
141
|
-
<div className="thumbnail-folder-label">{label}</div>
|
|
142
|
-
</Html>
|
|
143
|
-
)}
|
|
144
|
-
{!naming && !previewLabels && !mapMode && labelVisible && (
|
|
160
|
+
{!naming && !mapMode && labelVisible && (
|
|
145
161
|
<Text
|
|
146
162
|
position={[0, 0.05, -folder.depth / 2 + 1.6]}
|
|
147
163
|
rotation={[-Math.PI / 2, 0, 0]}
|
|
148
164
|
fontSize={0.55}
|
|
149
165
|
color={
|
|
150
|
-
|
|
166
|
+
pointedColor
|
|
167
|
+
? pointedColor
|
|
168
|
+
: highlight
|
|
169
|
+
? highlight.color
|
|
170
|
+
: addedOnly
|
|
171
|
+
? tint?.label ?? '#9ad8ff'
|
|
172
|
+
: '#8b95a5'
|
|
151
173
|
}
|
|
174
|
+
fillOpacity={opacity}
|
|
152
175
|
anchorX="center"
|
|
153
176
|
anchorY="middle"
|
|
154
177
|
>
|