feat: full-screen StoryGallery with flow layout, startAtScene engine method, clickable flow nodes
This commit is contained in:
@@ -7,8 +7,13 @@ const props = defineProps<{
|
||||
node: PlayerTreeNode | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
selectScene: [sceneId: string]
|
||||
}>()
|
||||
|
||||
interface FlowNode {
|
||||
id: string
|
||||
sceneId: string
|
||||
label: string
|
||||
visited: boolean
|
||||
isMystery: boolean
|
||||
@@ -33,7 +38,7 @@ const containerW = ref(800)
|
||||
const containerH = ref(400)
|
||||
|
||||
function buildFlow(root: PlayerTreeNode) {
|
||||
const dagreNodes: { id: string; parent: string | null; label: string; visited: boolean; isMystery: boolean; locked: boolean; lockHint?: string }[] = []
|
||||
const dagreNodes: { id: string; sceneId: string; parent: string | null; label: string; visited: boolean; isMystery: boolean; locked: boolean; lockHint?: string }[] = []
|
||||
const dagreEdges: { from: string; to: string; visited: boolean }[] = []
|
||||
|
||||
function walk(node: PlayerTreeNode, parentId: string | null) {
|
||||
@@ -41,6 +46,7 @@ function buildFlow(root: PlayerTreeNode) {
|
||||
const dagreId = parentId ? `${parentId}/${node.sceneId}` : node.sceneId
|
||||
dagreNodes.push({
|
||||
id: dagreId,
|
||||
sceneId: node.sceneId,
|
||||
parent: parentId,
|
||||
label: node.label,
|
||||
visited: true,
|
||||
@@ -65,6 +71,7 @@ function buildFlow(root: PlayerTreeNode) {
|
||||
const mysteryId = `${dagreId}/__mystery`
|
||||
dagreNodes.push({
|
||||
id: mysteryId,
|
||||
sceneId: '',
|
||||
parent: dagreId,
|
||||
label: '? ?',
|
||||
visited: false,
|
||||
@@ -100,6 +107,7 @@ function buildFlow(root: PlayerTreeNode) {
|
||||
const pos = g.node(n.id)
|
||||
return {
|
||||
id: n.id,
|
||||
sceneId: n.sceneId,
|
||||
label: n.label,
|
||||
visited: n.visited,
|
||||
isMystery: n.isMystery,
|
||||
@@ -221,9 +229,10 @@ const svgH = computed(() => containerH.value)
|
||||
v-for="n in nodes"
|
||||
:key="n.id"
|
||||
class="flow-node"
|
||||
:class="{ visited: n.visited, mystery: n.isMystery, locked: n.locked }"
|
||||
:class="{ visited: n.visited, mystery: n.isMystery, locked: n.locked, clickable: n.visited && n.sceneId }"
|
||||
:style="{ left: n.x + 'px', top: n.y + 'px', width: n.w + 'px', height: n.h + 'px' }"
|
||||
:title="n.lockHint || ''"
|
||||
@click="n.visited && n.sceneId && emit('selectScene', n.sceneId)"
|
||||
>
|
||||
<span class="node-icon">{{ n.visited ? '✦' : n.isMystery ? '?' : '⬜' }}</span>
|
||||
<span class="node-label">{{ n.label }}</span>
|
||||
@@ -264,6 +273,15 @@ const svgH = computed(() => containerH.value)
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.flow-node.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.flow-node.clickable:hover {
|
||||
background: rgba(201, 168, 76, 0.22);
|
||||
border-color: rgba(201, 168, 76, 0.5);
|
||||
}
|
||||
|
||||
.flow-node.visited {
|
||||
background: rgba(201, 168, 76, 0.12);
|
||||
border: 1px solid rgba(201, 168, 76, 0.3);
|
||||
|
||||
Reference in New Issue
Block a user