Files
Modrinth-plus/packages/ui/src/components/base/BaseTerminal.vue
2026-03-27 15:44:08 +00:00

102 lines
2.2 KiB
Vue

<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>