fix: resolve Pascal editor icons under base path

This commit is contained in:
134 2026-07-13 15:17:53 +08:00
parent 9cf84c324e
commit 663cb7c67a
8 changed files with 62 additions and 27 deletions

View File

@ -2,6 +2,7 @@
import { Icon } from '@iconify/react'
import { memo, useMemo } from 'react'
import { withEditorBasePath } from '../../lib/public-asset-path'
import useEditor, { type FloorplanSelectionTool } from '../../store/use-editor'
import { furnishTools } from '../ui/action-menu/furnish-tools'
import { tools as structureTools } from '../ui/action-menu/structure-tools'
@ -108,7 +109,7 @@ export const FloorplanCursorIndicatorOverlay = memo(function FloorplanCursorIndi
alt=""
aria-hidden="true"
className="h-5 w-5 object-contain drop-shadow-[0_2px_4px_rgba(0,0,0,0.5)]"
src={indicator.iconSrc}
src={withEditorBasePath(indicator.iconSrc)}
/>
) : (
<Icon
@ -142,7 +143,7 @@ export const FloorplanCursorIndicatorOverlay = memo(function FloorplanCursorIndi
alt=""
aria-hidden="true"
className="h-5 w-5 object-contain drop-shadow-[0_2px_4px_rgba(0,0,0,0.5)]"
src={indicator.iconSrc}
src={withEditorBasePath(indicator.iconSrc)}
/>
) : (
<Icon

View File

@ -659,7 +659,7 @@ function PaintCursorBadge({
alt=""
aria-hidden="true"
className="h-5 w-5 object-contain drop-shadow-[0_2px_4px_rgba(0,0,0,0.5)]"
src="/icons/paint.webp"
src={withEditorBasePath('/icons/paint.webp')}
style={{
filter: state === 'ready' ? undefined : 'grayscale(1)',
opacity: iconOpacity,

View File

@ -5,6 +5,7 @@ import type { Group } from 'three'
import { furnishTools } from '../../../components/ui/action-menu/furnish-tools'
import { tools } from '../../../components/ui/action-menu/structure-tools'
import { EDITOR_LAYER } from '../../../lib/constants'
import { withEditorBasePath } from '../../../lib/public-asset-path'
import useEditor from '../../../store/use-editor'
import useWallSnapIndicator from '../../../store/use-wall-snap-indicator'
@ -139,7 +140,7 @@ export const CursorSphere = forwardRef<Group, CursorSphereProps>(function Cursor
// eslint-disable-next-line @next/next/no-img-element
<img
alt={activeToolConfig!.label}
src={activeToolConfig!.iconSrc}
src={withEditorBasePath(activeToolConfig!.iconSrc)}
style={{
width: '100%',
height: '100%',

View File

@ -14,6 +14,7 @@ import { useViewer } from '@pascal-app/viewer'
import { Icon } from '@iconify/react'
import { Move, Trash2 } from 'lucide-react'
import { type ComponentType, lazy, Suspense, useCallback } from 'react'
import { withEditorBasePath } from '../../../lib/public-asset-path'
import { sfxEmitter } from '../../../lib/sfx-bus'
import { collectZoneContentIds } from '../../../lib/zone-content'
import useEditor from '../../../store/use-editor'
@ -229,7 +230,11 @@ function ParamActionButton({ action, nodeId }: { action: ParamAction<AnyNode>; n
className={disabled ? 'opacity-40 pointer-events-none' : ''}
icon={
action.iconSrc ? (
<img alt="" className="h-4 w-4 shrink-0 object-contain" src={action.iconSrc} />
<img
alt=""
className="h-4 w-4 shrink-0 object-contain"
src={withEditorBasePath(action.iconSrc)}
/>
) : undefined
}
label={action.label}

View File

@ -6,6 +6,7 @@ import {
TooltipContent,
TooltipTrigger,
} from './../../../components/ui/primitives/tooltip'
import { withEditorBasePath } from './../../../lib/public-asset-path'
import { cn } from './../../../lib/utils'
export type PanelId = string
@ -22,13 +23,13 @@ interface IconRailProps {
const sitePanel: { id: PanelId; iconSrc: string; label: string } = {
id: 'site',
iconSrc: '/icons/level.webp',
iconSrc: withEditorBasePath('/icons/level.webp'),
label: '场景',
}
const settingsPanel: { id: PanelId; iconSrc: string; label: string } = {
id: 'settings',
iconSrc: '/icons/settings.webp',
iconSrc: withEditorBasePath('/icons/settings.webp'),
label: '设置',
}

View File

@ -47,6 +47,7 @@ import {
squareMetersToAreaUnit,
} from './../../../../../lib/measurements'
import { createLocalGuideImage } from './../../../../../lib/local-guide-image'
import { withEditorBasePath } from './../../../../../lib/public-asset-path'
import { cn } from './../../../../../lib/utils'
import useEditor from './../../../../../store/use-editor'
import { useUploadStore } from '../../../../../store/use-upload'
@ -379,13 +380,13 @@ const ReferenceItem = memo(function ReferenceItem({
<img
alt="Scan"
className="h-3.5 w-3.5 shrink-0 object-contain opacity-70 transition-opacity group-hover/ref:opacity-100"
src="/icons/mesh.webp"
src={withEditorBasePath('/icons/mesh.webp')}
/>
) : (
<img
alt="Guide"
className="h-3.5 w-3.5 shrink-0 object-contain opacity-70 transition-opacity group-hover/ref:opacity-100"
src="/icons/floorplan.webp"
src={withEditorBasePath('/icons/floorplan.webp')}
/>
)}
<InlineRenameInput
@ -744,7 +745,7 @@ const LevelItem = memo(function LevelItem({
'h-4 w-4 shrink-0 object-contain transition-all duration-200',
!isSelected && 'opacity-60 grayscale',
)}
src="/icons/level.webp"
src={withEditorBasePath('/icons/level.webp')}
/>
<InlineRenameInput
defaultName={getDefaultLevelName(level.level)}
@ -1022,7 +1023,7 @@ const LayerToggle = memo(function LayerToggle() {
'mb-1 h-6 w-6 transition-all',
activeTab !== 'structure' && 'opacity-50 grayscale',
)}
src="/icons/room.webp"
src={withEditorBasePath('/icons/room.webp')}
/>
结构
</div>
@ -1058,7 +1059,7 @@ const LayerToggle = memo(function LayerToggle() {
'mb-1 h-6 w-6 transition-all',
activeTab !== 'furnish' && 'opacity-50 grayscale',
)}
src="/icons/couch.webp"
src={withEditorBasePath('/icons/couch.webp')}
/>
陈设
</div>
@ -1095,7 +1096,7 @@ const LayerToggle = memo(function LayerToggle() {
'mb-1 h-6 w-6 transition-all',
activeTab !== 'zones' && 'opacity-50 grayscale',
)}
src="/icons/kitchen.webp"
src={withEditorBasePath('/icons/kitchen.webp')}
/>
区域
</div>
@ -1436,7 +1437,7 @@ const BuildingItem = memo(function BuildingItem({
'h-5 w-5 object-contain transition-all',
!isBuildingActive && 'opacity-60 grayscale',
)}
src="/icons/building.webp"
src={withEditorBasePath('/icons/building.webp')}
/>
<span className="truncate font-medium text-sm">{building.name || '建筑'}</span>
</div>
@ -1592,7 +1593,7 @@ export function SitePanel({ projectId, onUploadAsset, onDeleteAsset }: SitePanel
'h-5 w-5 object-contain transition-all',
phase !== 'site' && 'opacity-60 grayscale',
)}
src="/icons/site-flag.webp"
src={withEditorBasePath('/icons/site-flag.webp')}
/>
<span className="font-medium text-sm">{siteNode.name || '场地'}</span>
</div>

View File

@ -1,14 +1,15 @@
import type { AnyNode, AssetInput } from '@pascal-app/core'
import type { ReactNode } from 'react'
import { withEditorBasePath } from '../../lib/public-asset-path'
import { cn } from '../../lib/utils'
export type SnapTarget = 'wall' | 'ceiling' | 'roof'
export type SnapTargetBadgeSize = 'tile' | 'tree'
const SNAP_TARGET_ICONS: Record<SnapTarget, string> = {
wall: '/icons/wall.webp',
ceiling: '/icons/ceiling.webp',
roof: '/icons/roof.webp',
wall: withEditorBasePath('/icons/wall.webp'),
ceiling: withEditorBasePath('/icons/ceiling.webp'),
roof: withEditorBasePath('/icons/roof.webp'),
}
const SNAP_TARGET_LABELS: Record<SnapTarget, string> = {

View File

@ -35,6 +35,7 @@ import {
import Link from 'next/link'
import { flushSync } from 'react-dom'
import { useShallow } from 'zustand/react/shallow'
import { withEditorBasePath } from '../lib/public-asset-path'
import { cn } from '../lib/utils'
import useEditor from '../store/use-editor'
import { ActionButton } from './ui/action-menu/action-button'
@ -88,25 +89,49 @@ const levelModeBadgeLabels: Record<'manual' | 'stacked' | 'exploded' | 'solo', s
const wallModeConfig = {
up: {
icon: (props: any) => (
<img alt="Full Height" height={28} src="/icons/room.webp" width={28} {...props} />
<img
alt="Full Height"
height={28}
src={withEditorBasePath('/icons/room.webp')}
width={28}
{...props}
/>
),
label: 'Full Height',
},
cutaway: {
icon: (props: any) => (
<img alt="Cutaway" height={28} src="/icons/wallcut.webp" width={28} {...props} />
<img
alt="Cutaway"
height={28}
src={withEditorBasePath('/icons/wallcut.webp')}
width={28}
{...props}
/>
),
label: 'Cutaway',
},
down: {
icon: (props: any) => (
<img alt="Low" height={28} src="/icons/walllow.webp" width={28} {...props} />
<img
alt="Low"
height={28}
src={withEditorBasePath('/icons/walllow.webp')}
width={28}
{...props}
/>
),
label: 'Low',
},
translucent: {
icon: (props: any) => (
<img alt="Translucent" height={28} src="/icons/wall.png" width={28} {...props} />
<img
alt="Translucent"
height={28}
src={withEditorBasePath('/icons/wall.webp')}
width={28}
{...props}
/>
),
label: 'Translucent',
},
@ -508,7 +533,7 @@ export const ViewerOverlay = ({
<img
alt="Scans"
className="h-[28px] w-[28px] object-contain"
src="/icons/mesh.webp"
src={withEditorBasePath('/icons/mesh.webp')}
/>
</ActionButton>
)}
@ -529,7 +554,7 @@ export const ViewerOverlay = ({
<img
alt="Guides"
className="h-[28px] w-[28px] object-contain"
src="/icons/floorplan.webp"
src={withEditorBasePath('/icons/floorplan.webp')}
/>
</ActionButton>
)}
@ -640,7 +665,7 @@ export const ViewerOverlay = ({
<img
alt="Orbit Left"
className="h-[28px] w-[28px] -scale-x-100 object-contain opacity-70 transition-opacity group-hover:opacity-100"
src="/icons/rotate.webp"
src={withEditorBasePath('/icons/rotate.webp')}
/>
</ActionButton>
@ -655,7 +680,7 @@ export const ViewerOverlay = ({
<img
alt="Orbit Right"
className="h-[28px] w-[28px] object-contain opacity-70 transition-opacity group-hover:opacity-100"
src="/icons/rotate.webp"
src={withEditorBasePath('/icons/rotate.webp')}
/>
</ActionButton>
@ -670,7 +695,7 @@ export const ViewerOverlay = ({
<img
alt="Top View"
className="h-[28px] w-[28px] object-contain opacity-70 transition-opacity group-hover:opacity-100"
src="/icons/topview.webp"
src={withEditorBasePath('/icons/topview.webp')}
/>
</ActionButton>