feat: console component (#5685)
This commit is contained in:
101
packages/ui/src/components/base/BaseTerminal.vue
Normal file
101
packages/ui/src/components/base/BaseTerminal.vue
Normal file
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex size-full flex-col bg-surface-2 overflow-hidden rounded-[20px] border border-solid border-surface-4"
|
||||
>
|
||||
<div class="relative min-h-0 pb-1 flex-1 overflow-hidden">
|
||||
<div ref="containerRef" class="size-full pl-2" />
|
||||
<div v-if="!isAtBottom" class="absolute bottom-4 right-4">
|
||||
<ButtonStyled circular type="highlight">
|
||||
<button class="!shadow-none" aria-label="Scroll to bottom" @click="scrollToBottom">
|
||||
<ChevronDownIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="showInput"
|
||||
class="border-t border-solid border-b-0 border-x-0 border-surface-5 bg-surface-3 p-4"
|
||||
>
|
||||
<StyledInput
|
||||
v-model="commandInput"
|
||||
:icon="TerminalSquareIcon"
|
||||
placeholder="Send a command"
|
||||
wrapper-class="w-full"
|
||||
input-class="!h-10"
|
||||
@keydown.enter="submitCommand"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ChevronDownIcon, TerminalSquareIcon } from '@modrinth/assets'
|
||||
import type { Terminal } from '@xterm/xterm'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
|
||||
import StyledInput from '#ui/components/base/StyledInput.vue'
|
||||
import { useTerminal } from '#ui/composables/terminal'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
scrollback?: number
|
||||
showInput?: boolean
|
||||
}>(),
|
||||
{
|
||||
scrollback: 10000,
|
||||
showInput: false,
|
||||
},
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
command: [command: string]
|
||||
ready: [terminal: Terminal]
|
||||
}>()
|
||||
|
||||
const containerRef = ref<HTMLElement | null>(null)
|
||||
const commandInput = ref('')
|
||||
|
||||
const { terminal, searchAddon, isAtBottom, write, writeln, clear, reset, fit, scrollToBottom } =
|
||||
useTerminal({
|
||||
container: containerRef,
|
||||
scrollback: props.scrollback,
|
||||
onReady: (term) => emit('ready', term),
|
||||
})
|
||||
|
||||
const submitCommand = () => {
|
||||
const cmd = commandInput.value.trim()
|
||||
if (!cmd) return
|
||||
emit('command', cmd)
|
||||
commandInput.value = ''
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
write,
|
||||
writeln,
|
||||
clear,
|
||||
reset,
|
||||
fit,
|
||||
scrollToBottom,
|
||||
terminal,
|
||||
searchAddon,
|
||||
isAtBottom,
|
||||
commandInput,
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.xterm {
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
.xterm .xterm-scrollable-element {
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen {
|
||||
min-height: 100% !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
}
|
||||
</style>
|
||||
@@ -5,6 +5,7 @@ export { default as AutoBrandIcon } from './AutoBrandIcon.vue'
|
||||
export { default as AutoLink } from './AutoLink.vue'
|
||||
export { default as Avatar } from './Avatar.vue'
|
||||
export { default as Badge } from './Badge.vue'
|
||||
export { default as BaseTerminal } from './BaseTerminal.vue'
|
||||
export { default as BigOptionButton } from './BigOptionButton.vue'
|
||||
export { default as BulletDivider } from './BulletDivider.vue'
|
||||
export { default as Button } from './Button.vue'
|
||||
|
||||
Reference in New Issue
Block a user