LogoPixi’VN

UI screen examples

All examples were created using basic HTML elements, you will need to replace them with UI components from your favorite library to improve the graphics.

Narrative dialogue UI screen

For example:

import { useQueryDialogue } from "../hooks/useQueryInterface";
import ChoiceMenu from "./ChoiceMenu";

export default function NarrationScreen() {
    const { data: { text, character } = {} } = useQueryDialogue();

    return (
        <div
            style={{
                position: "absolute",
                display: "flex",
                flexDirection: "column",
                height: "100%",
                width: "100%",
            }}
        >
            <div style={{ flex: 1, minHeight: 0 }}>
                {/* READ THIS: https://pixi-vn.web.app/start/choices.html#how-to-create-the-choice-menu-ui-screen */}
                <ChoiceMenu />
            </div>
            {text && (
                <div
                    style={{
                        flex: "0 0 auto",
                        height: "30%",
                        minHeight: 0,
                        pointerEvents: "auto",
                        backgroundColor: "white",
                        display: "flex",
                        flexDirection: "column",
                        overflow: "hidden",
                    }}
                >
                    {character && character.name && <b>{`${character?.name || ""} ${character?.surname || ""}`}</b>}
                    <div
                        style={{
                            display: "flex",
                            flexDirection: "row",
                            height: "100%",
                            minHeight: 0,
                            overflow: "hidden",
                        }}
                    >
                        {character?.icon && (
                            <img
                                src={character?.icon}
                                loading='lazy'
                                alt=''
                                style={{
                                    maxWidth: "30%",
                                    height: "auto",
                                    objectFit: "contain",
                                    display: "block",
                                }}
                            />
                        )}
                        <div style={{ flex: 1, minHeight: 0, overflow: "auto", height: "100%" }}>{text}</div>
                    </div>
                </div>
            )}
        </div>
    );
}

Choice menu UI screen

For example:

import useNarrationFunctions from "../hooks/useNarrationFunctions";
import { useQueryChoiceMenuOptions } from "../hooks/useQueryInterface";

export default function ChoiceMenu() {
    const { data: menu = [] } = useQueryChoiceMenuOptions();
    const { selectChoice } = useNarrationFunctions();

    return (
        <div
            style={{
                display: "flex",
                flexDirection: "column",
                justifyContent: "center",
                alignItems: "center",
                width: "100%",
                height: "100%",
                overflow: "auto",
                gap: "8px",
                maxHeight: "100%",
                margin: 0,
                pointerEvents: menu?.length > 0 ? "auto" : "none",
            }}
        >
            {menu?.map((item, index) => (
                <button
                    key={"choice-" + index}
                    style={{
                        justifyContent: "center",
                        alignItems: "center",
                    }}
                    onClick={() => selectChoice(item)}
                >
                    {item.text}
                </button>
            ))}
        </div>
    );
}

Go next button

For example:

import { useState } from "react";
import useNarrationFunctions from "../hooks/useNarrationFunctions";
import { useQueryCanGoNext } from "../hooks/useQueryInterface";

export default function NextButton() {
    const { data: canGoNext = false } = useQueryCanGoNext();
    const [loading, setLoading] = useState(false);
    const { goNext } = useNarrationFunctions();

    if (!canGoNext) {
        return null;
    }

    return (
        <button
            onClick={() => {
                setLoading(true);
                goNext()
                    .then(() => setLoading(false))
                    .catch(() => setLoading(false));
            }}
            disabled={loading}
            style={{
                width: 40,
                height: 20,
                pointerEvents: "auto",
            }}
        >
            Next
        </button>
    );
}

Go back button

For example:

import { useState } from "react";
import useNarrationFunctions from "../hooks/useNarrationFunctions";
import { useQueryCanGoBack } from "../hooks/useQueryInterface";

export default function BackButton() {
    const { data: canGoBack = false } = useQueryCanGoBack();
    const [loading, setLoading] = useState(false);
    const { goBack } = useNarrationFunctions();

    if (!canGoBack) {
        return null;
    }

    return (
        <button
            onClick={() => {
                setLoading(true);
                goBack()
                    .then(() => setLoading(false))
                    .catch(() => setLoading(false));
            }}
            disabled={loading}
            style={{
                width: 40,
                height: 20,
                pointerEvents: "auto",
            }}
        >
            Back
        </button>
    );
}

Input prompt dialog UI

For example:

import { narration } from "@drincs/pixi-vn";
import { useQueryClient } from "@tanstack/react-query";
import { useState } from "react";
import { INTERFACE_DATA_USE_QUEY_KEY, useQueryDialogue, useQueryInputValue } from "../../hooks/useQueryInterface";

export default function TextInput() {
    const { data: { text } = {} } = useQueryDialogue();
    const {
        data: { isRequired: open, currentValue } = {
            currentValue: undefined,
            isRequired: false,
        },
    } = useQueryInputValue<string | number>();
    const [tempValue, setTempValue] = useState<string | number>();
    const queryClient = useQueryClient();

    return (
        <dialog
            open={open}
            style={{
                pointerEvents: "auto",
            }}
        >
            <p>{text}</p>
            {open && (
                <input
                    defaultValue={currentValue || ""}
                    onChange={(e) => {
                        if (e && e.target && "value" in e.target) {
                            let value: any = e.target.value;
                            if ("type" in e.target && e.target.type === "number" && "valueAsNumber" in e.target) {
                                value = e.target.valueAsNumber;
                            }
                            setTempValue(value);
                        }
                    }}
                />
            )}
            <button
                onClick={() => {
                    narration.inputValue = tempValue || currentValue;
                    setTempValue(undefined);
                    queryClient.invalidateQueries({
                        queryKey: [INTERFACE_DATA_USE_QUEY_KEY],
                    });
                }}
            >
                Confirm
            </button>
        </dialog>
    );
}

History UI screen

For example:

import { Box, Stack } from "@mui/system";
import React from "react";
import { useQueryNarrativeHistory } from "../use_query/useQueryInterface";

export default function HistoryScreen() {
    const { data = [] } = useQueryNarrativeHistory();

    return (
        <dialog
            open={true}
            style={{
                height: "80%",
            }}
        >
            <Box
                sx={{
                    display: "flex",
                    flex: 1,
                    minHeight: 0,
                    px: 2,
                    py: 3,
                    overflowY: "scroll",
                    flexDirection: "column-reverse",
                    pointerEvents: "auto",
                    overflow: "auto",
                    height: "80%",
                }}
            >
                <Stack spacing={2} justifyContent="flex-end">
                {data.map((data, index) => {
                    return (
                    <React.Fragment key={"history" + index}>
                        <Stack direction="row" spacing={1.5}>
                            <img
                                src={data.icon}
                                loading="lazy"
                                alt=""
                                style={{
                                    verticalAlign: "middle",
                                    maxWidth: "50px",
                                    maxHeight: "50px",
                                    borderRadius: "50%",
                                }}
                            />
                            <Box sx={{ flex: 1 }}>
                                {data.character && data.character}
                                <div />
                                {data.text}
                            </Box>
                        </Stack>
                        <Stack direction="row" spacing={0.5}>
                            <Box sx={{ flex: 1 }}>
                                {data.choices &&
                                data.choices.map((choice, index) => {
                                    if (choice.hidden) {
                                        return null;
                                    }
                                    if (choice.isResponse) {
                                        return (
                                            <div
                                                key={"choices-success" + index}
                                                style={{
                                                    display: "inline-block",
                                                    padding: "5px 5px",
                                                    fontSize: "12px",
                                                    borderRadius: "25px",
                                                    backgroundColor: "#21ff3e",
                                                }}
                                            >
                                                {choice.text}
                                            </div>
                                        );
                                    }
                                    return (
                                        <div
                                            key={"choices" + index}
                                            style={{
                                                display: "inline-block",
                                                padding: "5px 5px",
                                                fontSize: "12px",
                                                borderRadius: "25px",
                                                backgroundColor: "#bcfdff",
                                            }}
                                        >
                                            {choice.text}
                                        </div>
                                    );
                                })}
                                {data.inputValue && (
                                    <div
                                        key={"choices-success" + index}
                                        style={{
                                            display: "inline-block",
                                            padding: "5px 5px",
                                            fontSize: "12px",
                                            borderRadius: "25px",
                                            backgroundColor: "#b0c2b2",
                                        }}
                                    >
                                        {data.inputValue.toString()}
                                    </div>
                                )}
                            </Box>
                        </Stack>
                    </React.Fragment>
                    );
                })}
                </Stack>
            </Box>
        </dialog>
    );
}