Skip to content

Commit fd7ae35

Browse files
committed
Maximizable code editor
1 parent 214a5fc commit fd7ae35

File tree

2 files changed

+170
-9
lines changed

2 files changed

+170
-9
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
<script setup lang="ts">
2+
import { ref, onMounted, onBeforeUnmount } from "vue";
3+
import CodeEditor from "@/components/CodeEditor.vue";
4+
import DiffMaximizeIcon from "@/assets/diff-maximize.svg";
5+
import DiffCloseIcon from "@/assets/diff-close.svg";
6+
import { Extension } from "@codemirror/state";
7+
import { CodeLanguage } from "@/components/codeEditorTypes";
8+
9+
// Define the model value to be passed to CodeEditor
10+
const modelValue = defineModel<string>({ required: true });
11+
12+
// Define props by extending the CodeEditor props and adding maximize-specific ones
13+
withDefaults(
14+
defineProps<{
15+
language?: CodeLanguage;
16+
readOnly?: boolean;
17+
showGutter?: boolean;
18+
showCopyToClipboard?: boolean;
19+
ariaLabel?: string;
20+
extensions?: Extension[];
21+
modalTitle?: string;
22+
}>(),
23+
{
24+
readOnly: false,
25+
showGutter: false,
26+
showCopyToClipboard: false,
27+
extensions: () => [],
28+
modalTitle: "Code View",
29+
}
30+
);
31+
32+
// Component state for maximize functionality
33+
const showMaximizeModal = ref(false);
34+
35+
// Handle maximize functionality
36+
const toggleMaximizeModal = () => {
37+
showMaximizeModal.value = !showMaximizeModal.value;
38+
};
39+
40+
// Handle ESC key to close modal
41+
const handleKeyDown = (event: KeyboardEvent) => {
42+
if (event.key === "Escape" && showMaximizeModal.value) {
43+
showMaximizeModal.value = false;
44+
}
45+
};
46+
47+
// Setup keyboard events for maximize modal
48+
onMounted(() => {
49+
window.addEventListener("keydown", handleKeyDown);
50+
});
51+
52+
// Clean up event listeners when component is destroyed
53+
onBeforeUnmount(() => {
54+
window.removeEventListener("keydown", handleKeyDown);
55+
});
56+
</script>
57+
58+
<template>
59+
<div class="code-editor-wrapper">
60+
<!-- Regular CodeEditor with maximize button in toolbarRight -->
61+
<CodeEditor v-model="modelValue" :language="language" :read-only="readOnly" :show-gutter="showGutter" :show-copy-to-clipboard="showCopyToClipboard" :aria-label="ariaLabel" :extensions="extensions">
62+
<template #toolbarLeft>
63+
<slot name="toolbarLeft"></slot>
64+
</template>
65+
<template #toolbarRight>
66+
<slot name="toolbarRight"></slot>
67+
<img class="maximize-icon-inline" :src="DiffMaximizeIcon" alt="Maximize" @click="toggleMaximizeModal" title="Maximize view" />
68+
</template>
69+
</CodeEditor>
70+
71+
<!-- Maximize modal for CodeEditor -->
72+
<div v-if="showMaximizeModal" class="maximize-modal">
73+
<div class="maximize-modal-content">
74+
<div class="maximize-modal-toolbar">
75+
<span class="maximize-modal-title">{{ modalTitle }}</span>
76+
<img class="maximize-modal-close" :src="DiffCloseIcon" alt="Close" @click="toggleMaximizeModal" title="Close" />
77+
</div>
78+
<div class="maximize-modal-body">
79+
<CodeEditor v-model="modelValue" :language="language" :read-only="readOnly" :show-copy-to-clipboard="true" :show-gutter="true" :aria-label="ariaLabel" :extensions="[]" />
80+
</div>
81+
</div>
82+
</div>
83+
</div>
84+
</template>
85+
86+
<style scoped>
87+
.code-editor-wrapper {
88+
position: relative;
89+
width: 100%;
90+
}
91+
92+
/* Maximize icon styles */
93+
.maximize-icon-inline {
94+
width: 14px;
95+
height: 14px;
96+
cursor: pointer;
97+
opacity: 0.7;
98+
transition: opacity 0.2s ease;
99+
margin-left: 8px;
100+
}
101+
102+
.maximize-icon-inline:hover {
103+
opacity: 1;
104+
}
105+
106+
/* Modal styles copied from DiffViewer */
107+
.maximize-modal {
108+
position: fixed;
109+
top: 0;
110+
left: 0;
111+
right: 0;
112+
bottom: 0;
113+
background-color: rgba(0, 0, 0, 0.5);
114+
z-index: 1000;
115+
display: flex;
116+
justify-content: center;
117+
align-items: center;
118+
}
119+
120+
.maximize-modal-content {
121+
background-color: white;
122+
width: calc(100% - 40px);
123+
height: calc(100% - 40px);
124+
border-radius: 4px;
125+
overflow: hidden;
126+
display: flex;
127+
flex-direction: column;
128+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
129+
}
130+
131+
.maximize-modal-toolbar {
132+
display: flex;
133+
justify-content: space-between;
134+
align-items: center;
135+
padding: 10px 15px;
136+
background-color: #f8f8f8;
137+
border-bottom: 1px solid #ddd;
138+
}
139+
140+
.maximize-modal-title {
141+
font-weight: bold;
142+
font-size: 16px;
143+
}
144+
145+
.maximize-modal-close {
146+
background: none;
147+
border: none;
148+
cursor: pointer;
149+
width: 16px;
150+
height: 16px;
151+
}
152+
153+
.maximize-modal-body {
154+
flex: 1;
155+
overflow: auto;
156+
padding: 15px;
157+
}
158+
159+
/* Ensure the CodeEditor wrapper fills the modal body */
160+
.maximize-modal-body :deep(.wrapper) {
161+
height: calc(100% - 20px);
162+
}
163+
164+
.maximize-modal-body :deep(.cm-editor),
165+
.maximize-modal-body :deep(.cm-scroller) {
166+
height: 100%;
167+
}
168+
</style>

src/Frontend/src/components/messages2/SagaDiagram/SagaUpdateNode.vue

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import MessageDataBox from "./MessageDataBox.vue";
44
import SagaOutgoingTimeoutMessage from "./SagaOutgoingTimeoutMessage.vue";
55
import SagaOutgoingMessage from "./SagaOutgoingMessage.vue";
66
import DiffViewer from "@/components/messages2/DiffViewer.vue";
7-
import CodeEditor from "@/components/CodeEditor.vue";
7+
import MaximizableCodeEditor from "@/components/MaximizableCodeEditor.vue";
88
import { useSagaDiagramStore } from "@/stores/SagaDiagramStore";
99
import { ref, watch, computed } from "vue";
1010
import { EditorView } from "@codemirror/view";
@@ -35,13 +35,6 @@ const monospaceTheme = EditorView.baseTheme({
3535
},
3636
});
3737
38-
// Define types for JSON values and properties
39-
type JsonValue = string | number | boolean | null | JsonObject | JsonArray;
40-
interface JsonObject {
41-
[key: string]: JsonValue;
42-
}
43-
type JsonArray = Array<JsonValue>;
44-
4538
const props = defineProps<{
4639
update: SagaUpdateViewModel;
4740
showMessageData?: boolean;
@@ -202,7 +195,7 @@ const hasStateChanges = computed(() => {
202195

203196
<!-- Initial state display -->
204197
<div v-else-if="update.IsFirstNode" class="json-container json-container--first-node">
205-
<CodeEditor :model-value="sagaUpdateStateChanges.formattedState || ''" language="json" :showCopyToClipboard="false" :showGutter="false" :extensions="[monospaceTheme]" />
198+
<MaximizableCodeEditor :model-value="sagaUpdateStateChanges.formattedState || ''" language="json" :showCopyToClipboard="false" :showGutter="false" modalTitle="Saga Initialized" :extensions="[monospaceTheme]" />
206199
</div>
207200

208201
<!-- No changes message -->

0 commit comments

Comments
 (0)