mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 18:34:03 +03:00
Code editor open-close improvements (#9365)
Closes #9209 https://github.com/enso-org/enso/assets/6566674/43984978-004b-4ed2-a55e-de9302dc1fdd - Added new menu item `Code editor` which toggles visibility of, well, code editor - Changed the menu implementation: - Fixed platform-dependent “More” icon. It was displayed awfully on Mac. - Added simple opacity animation. - Reduced width slightly. - Refactored the layout, removed unused classes and CSS… - Added animated background when hovering “Show all” icon - Added close button to the upper left corner of the code editor (upper right is occupied by resize controls)
This commit is contained in:
parent
1b59744660
commit
b33079e68b
@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { ChangeSet, Diagnostic, Highlighter } from '@/components/CodeEditor/codemirror'
|
||||
import SvgIcon from '@/components/SvgIcon.vue'
|
||||
import { usePointer } from '@/composables/events'
|
||||
import { useGraphStore, type NodeId } from '@/stores/graph'
|
||||
import { useProjectStore } from '@/stores/project'
|
||||
@ -38,6 +39,8 @@ const {
|
||||
textEditToChangeSpec,
|
||||
} = await import('@/components/CodeEditor/codemirror')
|
||||
|
||||
const emit = defineEmits<{ close: [] }>()
|
||||
|
||||
const projectStore = useProjectStore()
|
||||
const graphStore = useGraphStore()
|
||||
const suggestionDbStore = useSuggestionDbStore()
|
||||
@ -347,6 +350,7 @@ const editorStyle = computed(() => {
|
||||
<circle cx="14" cy="14" r="1.5" />
|
||||
</svg>
|
||||
</div>
|
||||
<SvgIcon name="enso_logo" class="closeButton button" @click="emit('close')" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -403,6 +407,18 @@ const editorStyle = computed(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.closeButton {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 6px;
|
||||
color: red;
|
||||
opacity: 0.3;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.CodeEditor :deep(.cm-editor) {
|
||||
position: relative;
|
||||
color: white;
|
||||
|
@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import SvgIcon from '@/components/SvgIcon.vue'
|
||||
import { isMacLike } from '@/composables/events'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const isDropdownOpen = ref(false)
|
||||
@ -7,44 +8,50 @@ const isDropdownOpen = ref(false)
|
||||
const props = defineProps<{
|
||||
zoomLevel: number
|
||||
}>()
|
||||
const emit = defineEmits<{ zoomIn: []; zoomOut: []; fitToAllClicked: [] }>()
|
||||
const emit = defineEmits<{ zoomIn: []; zoomOut: []; fitToAllClicked: []; toggleCodeEditor: [] }>()
|
||||
|
||||
// TODO: replace with codeEditorBindigs.toggle: https://github.com/enso-org/enso/issues/9411.
|
||||
const toggleCodeEditorShortcut = isMacLike ? 'Cmd + `' : 'Ctrl + `'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="ExtendedMenu">
|
||||
<div class="moreIcon" @pointerdown="isDropdownOpen = !isDropdownOpen"></div>
|
||||
<Transition name="dropdown">
|
||||
<div v-show="isDropdownOpen" class="ExtendedMenuPane">
|
||||
<div class="row">
|
||||
<div class="zoomBar row">
|
||||
<div class="label">Zoom</div>
|
||||
<div class="zoomControl last">
|
||||
<div
|
||||
class="zoomButton minus"
|
||||
title="Decrease zoom"
|
||||
@pointerdown.stop="emit('zoomOut')"
|
||||
/>
|
||||
<span
|
||||
class="zoomScaleLabel"
|
||||
v-text="props.zoomLevel ? props.zoomLevel.toFixed(0) + '%' : '?'"
|
||||
></span>
|
||||
<div
|
||||
class="zoomButton plus"
|
||||
title="increase zoom"
|
||||
@pointerdown.stop="emit('zoomIn')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ExtendedMenu"
|
||||
@pointerdown.stop
|
||||
@pointerup.stop
|
||||
@click.stop="isDropdownOpen = !isDropdownOpen"
|
||||
>
|
||||
<SvgIcon name="folder_opened" class="moreIcon" />
|
||||
</div>
|
||||
<Transition name="dropdown">
|
||||
<div
|
||||
v-show="isDropdownOpen"
|
||||
class="ExtendedMenuPane"
|
||||
@pointerdown.stop
|
||||
@pointerup.stop
|
||||
@click.stop
|
||||
>
|
||||
<div class="row">
|
||||
<div class="label">Zoom</div>
|
||||
<div class="zoomControl">
|
||||
<div class="zoomButton minus" title="Decrease zoom" @click="emit('zoomOut')" />
|
||||
<span
|
||||
class="zoomScaleLabel"
|
||||
v-text="props.zoomLevel ? props.zoomLevel.toFixed(0) + '%' : '?'"
|
||||
></span>
|
||||
<div class="zoomButton plus" title="increase zoom" @click="emit('zoomIn')" />
|
||||
<div class="divider"></div>
|
||||
<SvgIcon
|
||||
name="show_all"
|
||||
class="last showAllIcon"
|
||||
@pointerdown="emit('fitToAllClicked')"
|
||||
/>
|
||||
<div class="showAllIconHighlight">
|
||||
<SvgIcon name="show_all" class="showAllIcon" @click="emit('fitToAllClicked')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
<div class="row clickableRow" @click="emit('toggleCodeEditor')">
|
||||
<div class="label">Code Editor</div>
|
||||
<div>{{ toggleCodeEditorShortcut }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@ -56,32 +63,34 @@ const emit = defineEmits<{ zoomIn: []; zoomOut: []; fitToAllClicked: [] }>()
|
||||
height: 32px;
|
||||
margin-left: auto;
|
||||
margin-right: 125px;
|
||||
}
|
||||
|
||||
.ExtendedMenu:before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
border-radius: var(--radius-full);
|
||||
background: var(--color-frame-bg);
|
||||
backdrop-filter: var(--blur-app-bg);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ExtendedMenuPane {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
width: 300px;
|
||||
flex-direction: column;
|
||||
width: 250px;
|
||||
top: 40px;
|
||||
margin-top: 6px;
|
||||
padding: 4px;
|
||||
right: 0px;
|
||||
|
||||
border-radius: var(--radius-full);
|
||||
border-radius: 12px;
|
||||
background: var(--color-frame-bg);
|
||||
backdrop-filter: var(--blur-app-bg);
|
||||
}
|
||||
|
||||
.clickableRow {
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
&:hover {
|
||||
background-color: var(--color-menu-entry-hover-bg);
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
@ -90,14 +99,10 @@ const emit = defineEmits<{ zoomIn: []; zoomOut: []; fitToAllClicked: [] }>()
|
||||
.row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
padding-left: 4px;
|
||||
padding: 0 8px 0 8px;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.last {
|
||||
margin-left: auto;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.divider {
|
||||
@ -115,9 +120,20 @@ const emit = defineEmits<{ zoomIn: []; zoomOut: []; fitToAllClicked: [] }>()
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.showAllIcon {
|
||||
margin-right: 10px;
|
||||
.showAllIconHighlight {
|
||||
display: flex;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
padding-left: 4px;
|
||||
cursor: pointer;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin: -4px -4px;
|
||||
border-radius: var(--radius-full);
|
||||
transition: background-color 0.3s;
|
||||
&:hover {
|
||||
background-color: var(--color-menu-entry-hover-bg);
|
||||
}
|
||||
}
|
||||
|
||||
.zoomScaleLabel {
|
||||
@ -126,18 +142,8 @@ const emit = defineEmits<{ zoomIn: []; zoomOut: []; fitToAllClicked: [] }>()
|
||||
}
|
||||
|
||||
.moreIcon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
font-family: var(--font-code);
|
||||
position: relative;
|
||||
right: -4px;
|
||||
top: 8px;
|
||||
}
|
||||
|
||||
.moreIcon:before {
|
||||
content: '\2807';
|
||||
left: 8px;
|
||||
}
|
||||
|
||||
.zoomButton {
|
||||
@ -187,4 +193,14 @@ const emit = defineEmits<{ zoomIn: []; zoomOut: []; fitToAllClicked: [] }>()
|
||||
margin: auto 2px;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
.dropdown-enter-active,
|
||||
.dropdown-leave-active {
|
||||
transition: opacity 0.25s ease;
|
||||
}
|
||||
|
||||
.dropdown-enter-from,
|
||||
.dropdown-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
@ -292,9 +292,12 @@ const { handleClick } = useDoubleClick(
|
||||
)
|
||||
const codeEditorArea = ref<HTMLElement>()
|
||||
const showCodeEditor = ref(false)
|
||||
const toggleCodeEditor = () => {
|
||||
showCodeEditor.value = !showCodeEditor.value
|
||||
}
|
||||
const codeEditorHandler = codeEditorBindings.handler({
|
||||
toggle() {
|
||||
showCodeEditor.value = !showCodeEditor.value
|
||||
toggleCodeEditor()
|
||||
},
|
||||
})
|
||||
|
||||
@ -595,11 +598,12 @@ function handleEdgeDrop(source: AstId, position: Vec2) {
|
||||
@fitToAllClicked="zoomToSelected"
|
||||
@zoomIn="graphNavigator.stepZoom(+1)"
|
||||
@zoomOut="graphNavigator.stepZoom(-1)"
|
||||
@toggleCodeEditor="toggleCodeEditor"
|
||||
/>
|
||||
<PlusButton @pointerdown.stop @click.stop="addNodeAuto()" @pointerup.stop />
|
||||
<Transition>
|
||||
<Suspense ref="codeEditorArea">
|
||||
<CodeEditor v-if="showCodeEditor" />
|
||||
<CodeEditor v-if="showCodeEditor" @close="showCodeEditor = false" />
|
||||
</Suspense>
|
||||
</Transition>
|
||||
<SceneScroller
|
||||
|
@ -22,6 +22,7 @@ const emit = defineEmits<{
|
||||
fitToAllClicked: []
|
||||
zoomIn: []
|
||||
zoomOut: []
|
||||
toggleCodeEditor: []
|
||||
}>()
|
||||
|
||||
const LEFT_PADDING_PX = 11
|
||||
@ -56,6 +57,7 @@ const barStyle = computed(() => {
|
||||
@fitToAllClicked="emit('fitToAllClicked')"
|
||||
@zoomIn="emit('zoomIn')"
|
||||
@zoomOut="emit('zoomOut')"
|
||||
@toggleCodeEditor="emit('toggleCodeEditor')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
Loading…
Reference in New Issue
Block a user