mock: バリアントの既定の印・バッジ・作成先を直す(T-30 単位3)
ポップオーバーの既定の印を「既定」の札にする。バッジには名前を書かず、 表示中のバリアント名はツールチップで示す(はみ出しをなくす。T-30の着手前の決定を反映)。 バリアントグループは選択の入れ物(クラスター・バリアント)の中に作る。 そのため domain に createVariantGroupInParent を足し、variant のIDを渡すと 例外になっていた parentNodes を直した。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NznQtmVPoQAnietqwr1auL
This commit is contained in:
@@ -114,9 +114,12 @@ export function insertNodes(f: PhyFile, parentId: string | null, nodes: Node[],
|
||||
|
||||
function parentNodes(f: PhyFile, parentId: string | null): Node[] {
|
||||
if (!parentId) return f.root;
|
||||
const n = find(f, parentId);
|
||||
if (n.type === "cluster") return n.children;
|
||||
if (n.type === "variantGroup") throw new Error("Choose a variant as the parent");
|
||||
// variantのIDは containers に子の入れ物として載るので、find ではノードとして引けない
|
||||
const n = containers(f)
|
||||
.get(parentId)
|
||||
?.nodes.find((x) => x.id === parentId);
|
||||
if (n?.type === "cluster") return n.children;
|
||||
if (n?.type === "variantGroup") throw new Error("Choose a variant as the parent");
|
||||
return findVariant(f, parentId).children;
|
||||
}
|
||||
/** ローカル座標の差分でノードを移動する。 */
|
||||
@@ -397,6 +400,17 @@ export function createVariantGroup(
|
||||
at: Transform,
|
||||
variants: [{ name: string; children?: Node[] }, { name: string; children?: Node[] }],
|
||||
gen?: () => string,
|
||||
): PhyFile {
|
||||
return createVariantGroupInParent(f, null, name, at, variants, gen);
|
||||
}
|
||||
/** 指定コンテナへVariantGroupを作成する。T-11。 */
|
||||
export function createVariantGroupInParent(
|
||||
f: PhyFile,
|
||||
parentId: string | null,
|
||||
name: string,
|
||||
at: Transform,
|
||||
variants: [{ name: string; children?: Node[] }, { name: string; children?: Node[] }],
|
||||
gen?: () => string,
|
||||
): PhyFile {
|
||||
const o = mutable(f),
|
||||
children = variants.map((x) => ({
|
||||
@@ -405,7 +419,7 @@ export function createVariantGroup(
|
||||
name: x.name,
|
||||
children: structuredClone(x.children ?? []),
|
||||
}));
|
||||
o.root.push({
|
||||
parentNodes(o, parentId).push({
|
||||
type: "variantGroup",
|
||||
id: nodeId("variantGroup", gen),
|
||||
name,
|
||||
|
||||
@@ -28,7 +28,7 @@ function bounds(n: Node) {
|
||||
}
|
||||
function badgeBox(n: Node) {
|
||||
const b = bounds(n);
|
||||
const size = 26 / props.zoom;
|
||||
const size = 20 / props.zoom;
|
||||
return {
|
||||
x: b.x + b.width + 4 / props.zoom,
|
||||
y: b.y - size - 4 / props.zoom,
|
||||
@@ -36,6 +36,12 @@ function badgeBox(n: Node) {
|
||||
angle: -(props.angle + n.transform.rotation),
|
||||
};
|
||||
}
|
||||
/** バッジは名前を書かず、表示中のバリアント名はツールチップで示す。T-30。 */
|
||||
function badgeTitle(n: Extract<Node, { type: "variantGroup" }>) {
|
||||
const shown = props.variants[n.id] || n.default;
|
||||
const name = n.children.find((v) => v.id === shown)?.name ?? "";
|
||||
return `${n.name}: ${name}${shown === n.default ? "(既定)" : ""}`;
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<g
|
||||
@@ -135,15 +141,14 @@ function badgeBox(n: Node) {
|
||||
:y="badgeBox(n).y"
|
||||
:width="badgeBox(n).size"
|
||||
:height="badgeBox(n).size"
|
||||
rx="3"
|
||||
:rx="3 / zoom"
|
||||
@click.stop="emit('badge', n, $event)"
|
||||
/><text
|
||||
:x="badgeBox(n).x + 3 / zoom"
|
||||
:y="badgeBox(n).y + 16 / zoom"
|
||||
:x="badgeBox(n).x + badgeBox(n).size / 2"
|
||||
:y="badgeBox(n).y + badgeBox(n).size / 2"
|
||||
:style="{ fontSize: `${12 / zoom}px` }"
|
||||
>{{ n.children.find((v) => v.id === (variants[n.id] || n.default))?.name
|
||||
}}{{ n.default === (variants[n.id] || n.default) ? " ✓" : "" }}</text
|
||||
></g
|
||||
>⇄</text
|
||||
><title>{{ badgeTitle(n) }}</title></g
|
||||
></g
|
||||
>
|
||||
</g>
|
||||
@@ -213,6 +218,8 @@ function badgeBox(n: Node) {
|
||||
.badge text {
|
||||
font-size: 12px;
|
||||
fill: #302709;
|
||||
text-anchor: middle;
|
||||
dominant-baseline: central;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -431,7 +431,7 @@ function onFocus(_id: string) {
|
||||
>
|
||||
<template v-for="g in variantGroups.filter((n) => n.id === popover)" :key="g.id"
|
||||
><button v-for="v in g.children" :key="v.id" @click="chooseVariant(g, v.id)">
|
||||
{{ v.name }} {{ g.default === v.id ? "✓" : "" }}
|
||||
{{ v.name }}<span v-if="g.default === v.id" class="default-tag">既定</span>
|
||||
</button></template
|
||||
>
|
||||
</div>
|
||||
@@ -581,6 +581,14 @@ function onFocus(_id: string) {
|
||||
.warning {
|
||||
color: #9a4c00;
|
||||
}
|
||||
.default-tag {
|
||||
margin-left: 6px;
|
||||
padding: 0 4px;
|
||||
border: 1px solid #8a691b;
|
||||
border-radius: 3px;
|
||||
font-size: 11px;
|
||||
color: #6b520f;
|
||||
}
|
||||
.long-label {
|
||||
position: fixed;
|
||||
z-index: 3;
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
addKeyToParent,
|
||||
clusterNodes,
|
||||
cloneNodesWithNewIds,
|
||||
createVariantGroup,
|
||||
createVariantGroupInParent,
|
||||
insertNodes,
|
||||
reparent,
|
||||
reparentToVariant,
|
||||
@@ -205,12 +205,16 @@ export function usePhyCommands(options: Options) {
|
||||
|
||||
function variantGroup() {
|
||||
if (!options.selected.value.length) return;
|
||||
const parent = options.selectedContainer(options.selected.value[0]!);
|
||||
let id = "";
|
||||
options.dispatch("バリアントグループ作成", (project) => {
|
||||
let phy = createVariantGroup(project.phy, "Variant Group", { x: 0, y: 0, rotation: 0 }, [
|
||||
{ name: "Option A" },
|
||||
{ name: "Option B" },
|
||||
]);
|
||||
let phy = createVariantGroupInParent(
|
||||
project.phy,
|
||||
parent,
|
||||
"Variant Group",
|
||||
{ x: 0, y: 0, rotation: 0 },
|
||||
[{ name: "Option A" }, { name: "Option B" }],
|
||||
);
|
||||
const group = options
|
||||
.allNodes(phy.root)
|
||||
.find(
|
||||
|
||||
Reference in New Issue
Block a user