feat: add auto furniture interaction detection
- New auto-interaction.ts: detects canSit/canLay/canStand from classname/name keywords - Maps keywords to interaction types (bench, chair, bed, table, etc.) - Returns clickLimit and interactionModesCount for proper click/interaction limits - Nitro editor: added auto-detect button with preview of detected settings - furni-import.ts: auto-sets interaction_modes_count during import - upload-import.ts: auto-detects for direct insert and SQL migrations - clone-import.ts: auto-detects when cloning from other hotels
This commit is contained in:
1 parent
0b4fc4559e
commit
dee843106f
8 files changed
+596
-25
No files matched your search
@@ -32,9 +32,14 @@ import { Switch } from "@/components/ui/switch";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { adminFetch } from "@/lib/admin-fetch";
|
||||
import {
|
||||
autoDetectInteraction,
|
||||
getInteractionTypeLabel,
|
||||
} from "@/lib/furni/auto-interaction";
|
||||
|
||||
interface NitroEditorDialogProps {
|
||||
classname: string;
|
||||
name?: string;
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
}
|
||||
@@ -122,6 +127,7 @@ function CopyClassname({ value }: { value: string }) {
|
||||
|
||||
export function NitroEditorDialog({
|
||||
classname,
|
||||
name = "",
|
||||
open,
|
||||
onOpenChange,
|
||||
}: NitroEditorDialogProps) {
|
||||
@@ -142,8 +148,22 @@ export function NitroEditorDialog({
|
||||
cansiton: false,
|
||||
canlayon: false,
|
||||
});
|
||||
const [autoDetectResult, setAutoDetectResult] = useState<ReturnType<
|
||||
typeof autoDetectInteraction
|
||||
> | null>(null);
|
||||
const [jsonError, setJsonError] = useState<string | null>(null);
|
||||
|
||||
const handleAutoDetect = () => {
|
||||
const result = autoDetectInteraction(classname, name);
|
||||
setAutoDetectResult(result);
|
||||
setFlags({
|
||||
canstandon: result.canStand,
|
||||
cansiton: result.canSit,
|
||||
canlayon: result.canLay,
|
||||
});
|
||||
toast.success(`Auto-detected: ${result.reason}`);
|
||||
};
|
||||
|
||||
const patchMeta = (path: string, value: unknown) => {
|
||||
setMetadata((prev) =>
|
||||
prev == null ? prev : updateNested(prev, path, value),
|
||||
@@ -497,6 +517,53 @@ export function NitroEditorDialog({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleAutoDetect}
|
||||
className="gap-1.5 w-full"
|
||||
>
|
||||
<Sparkles className="w-3.5 h-3.5" />
|
||||
Auto-detect from name
|
||||
</Button>
|
||||
{autoDetectResult && (
|
||||
<div className="rounded-md bg-muted/50 p-3 text-xs space-y-1">
|
||||
<div className="flex items-center gap-1.5 flex-wrap">
|
||||
<Badge
|
||||
variant={
|
||||
autoDetectResult.canLay ? "default" : "secondary"
|
||||
}
|
||||
className="gap-1"
|
||||
>
|
||||
{autoDetectResult.canLay ? (
|
||||
<Layers className="w-2.5 h-2.5" />
|
||||
) : autoDetectResult.canSit ? (
|
||||
<MousePointerClick className="w-2.5 h-2.5" />
|
||||
) : (
|
||||
<MousePointerClick className="w-2.5 h-2.5" />
|
||||
)}
|
||||
{getInteractionTypeLabel(
|
||||
autoDetectResult.interactionType,
|
||||
)}
|
||||
</Badge>
|
||||
{autoDetectResult.clickLimit > 0 && (
|
||||
<Badge variant="outline" className="gap-1">
|
||||
Click limit: {autoDetectResult.clickLimit}
|
||||
</Badge>
|
||||
)}
|
||||
{autoDetectResult.interactionModesCount > 0 && (
|
||||
<Badge variant="outline" className="gap-1">
|
||||
Modes: {autoDetectResult.interactionModesCount}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-muted-foreground">
|
||||
{autoDetectResult.reason}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in new issue
Block a user