vue+python实现类似cursor的ai编程助手前端交互html代码
代码语言:html
所属分类:其他
代码描述:vue+python实现类似cursor的ai编程助手前端交互html代码
代码标签: vue python 类似 cursor ai 编程 助手 前端 交互 html 代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Code Editor</title>
<link rel='stylesheet' href='//repo.bfw.wiki/bfwrepo/js/codemirror/lib/codemirror.css'>
<link rel='stylesheet' href='//repo.bfw.wiki/bfwrepo/js/codemirror/theme/material.css'>
<style>
.maineditor {
display: flex;
flex-direction: row;
height: 100vh;
width: 100vw;
overflow: hidden;
}
.selected-label {
color: green;
margin-left: 10px;
}
/* 自定义滚动条样式 */
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: #1e1e1e;
border-radius: 5px;
}
::-webkit-scrollbar-thumb {
background: #444;
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
/* Firefox 滚动条样式 */
* {
scrollbar-color: #444 #1e1e1e;
scrollbar-width: thin;
}
body {
margin: 0;
padding: 0;
display: flex;
height: 100vh;
font-family: Arial, sans-serif;
background-color: #1e1e1e;
color: white;
overflow: hidden;
}
#sidebar {
width: 250px;
background-color: #252526;
padding: 10px;
overflow-y: auto;
border-right: 1px solid #444;
}
#editor {
flex: 1;
background-color: #1e1e1e;
display: flex;
flex-direction: column;
overflow: hidden;
}
.file-item,
.folder-item,
.project-item {
cursor: pointer;
padding: 5px;
margin: 5px 0;
border-radius: 3px;
display: flex;
align-items: center;
}
.file-item:hover,
.folder-item:hover,
.project-item:hover {
background-color: #2a2d2e;
}
.context-btn {
margin-left: 10px;
cursor: pointer;
color: #ccc;
font-size: 12px;
}
.folder-item::before,
.file-item::before {
content: '';
display: inline-block;
width: 16px;
height: 16px;
margin-right: 5px;
background-size: cover;
}
.folder-item::before {
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik0xMCA0SDRjLTEuMSAwLTEuOTkuOS0xLjk5IDJMMiAxOGMwIDEuMS45IDIgMiAyaDE2YzEuMSAwIDItLjkgMi0yVjhjMC0xLjEtLjktMi0yLTJoLThsLTItMnoiLz48L3N2Zz4=');
}
.file-item::before {
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik0xNCAySDZjLTEuMSAwLTEuOTkuOS0xLjk5IDJMMyAyMGMwIDEuMS45IDIgMiAyaDEyYzEuMSAwIDItLjkgMi0yVjhsLTYtNnptNCAxOEg2VjRoN3Y1aDV2MTF6Ii8+PC9zdmc+');
}
.folder-item.collapsed::before {
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik0xMCA4SDRjLTEuMSAwLTEuOTkuOS0xLjk5IDJMMiAxOGMwIDEuMS45IDIgMiAyaDE2YzEuMSAwIDItLjkgMi0yVjhjMC0xLjEtLjktMi0yLTJoLThsLTItMnoiLz48L3N2Zz4=');
}
.folder-item.expanded::before {
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik0xOSAxMEg1Yy0xLjEgMC0yIC45LTIgMnY4YzAgMS4xLjkgMiAyIDJoMTRjMS4xIDAgMi0uOSAyLTJ2LThjMC0xLjEtLjktMi0yLTJ6bS04IDZIOXYtMmgydjJ6bTAtNEg5di0yaDJ2MnptNC40IDRoLTMuOGMtLjMgMC0uNi0uMi0uOC0uNGwtMS4yLTEuNmgxLjJsLjYuOWg4LjJsLjYtLjkxIDEuMiAxLjYxYy0uMi4yLS41LjQtLjguNHoiLz48L3N2Zz4=');
}
#tabs {
display: flex;
background-color: #252526;
padding: 5px;
border-bottom: 1px solid #444;
}
.tab {
display: flex;
align-items: center;
padding: 8px 12px;
margin-right: 5px;
cursor: pointer;
background-color: #2a2d2e;
border-radius: 3px;
position: relative;
}
.tab.active {
background-color: #0e639c;
}
.close-button {
margin-left: 8px;
cursor: pointer;
font-size: 14px;
color: #ccc;
}
.close-button:hover {
color: white;
}
#save-button {
position: absolute;
top: 10px;
right: 10px;
background-color: #0e639c;
color: white;
border: none;
padding: 8px 12px;
border-radius: 3px;
cursor: pointer;
}
#save-button:hover {
background-color: #1177bb;
}
.CodeMirror {
height: 100%;
/* 确保编辑器占据整个容器高度 */
}
.sub-container {
margin-left: 20px;
display: none;
}
.folder-item.expanded+.sub-container {
display: block;
}
#code-editor-container {
flex: 1;
/* 默认隐藏 */
height: 100vh;
overflow: hidden;
}
#code-editor-container.active {
display: block;
/* 显示编辑器容器 */
}
.code-editor-wrapper {
height: 100%;
/* 确保编辑器占据整个容器高度 */
}
/* 聊天窗口样式 */
#chat-window {
position: fixed;
bottom: 20px;
right: 20px;
width: 300px;
height: 600px;
background-color: #252526;
border: 1px solid #444;
border-radius: 5px;
display: flex;
flex-direction: column;
overflow: hidden;
z-index: 1000;
}
#chat-icon {
position: fixed;
bottom: 20px;
right: 20px;
cursor: pointer;
}
#minimize-btn {
float: right;
background: none;
border: none;
font-size: 20px;
cursor: pointer;
}
/* 开关样式 */
.switch {
position: relative;
display: inline-block;
width: 40px;
height: 18px;
margin-left: 10px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #444;
transition: 0.4s;
border-radius: 18px;
}
.slider:before {
position: absolute;
content: '';
height: 14px;
width: 14px;
left: 2px;
bottom: 2px;
background-color: white;
transition: 0.4s;
border-radius: 50%;
}
input:checked+.slider {
background-color: #0e639c;
}
input:checked+.slider:before {
transform: translateX(20px);
}
/* 开关标签样式 */
.switch-label {
display: flex;
align-items: center;
color: white;
font-size: 12px;
}
/* 聊天窗口头部布局 */
#chat-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
background-color: #1e1e1e;
cursor: move;
border-bottom: 1px solid #444;
}
#chat-body {
flex: 1;
padding: 10px;
overflow-y: auto;
background-color: #252526;
font-size: 12px;
line-height: 20px;
}
#chat-body ol,
#chat-body ul {
margin: 0;
padding: 10px;
}
#chat-input {
padding: 10px;
background-color: #1e1e1e;
border-top: 1px solid #444;
}
#chat-input textarea {
width: 100%;
height: 50px;
background-color: #252526;
color: white;
border: 1px solid #444;
border-radius: 3px;
padding: 5px;
}
.message {
margin-bottom: 10px;
word-wrap: break-word;
}
.message.user {
color: #4CAF50;
}
.message.ai {
color: #2196F3;
}
/* 代码块样式 */
.message.ai pre {
position: relative;
background-color: #1e1e1e;
padding: 10px;
border-radius: 5px;
overflow-x: auto;
}
.message.ai code {
font-family: monospace;
background-color: #1e1e1e;
padding: 2px 4px;
border-radius: 3px;
}
/* 复制按钮样式 */
.copy-button {
position: absolute;
top: 5px;
right: 5px;
background-color: #444;
color: white;
border: none;
padding: 5px 10px;
border-radius: 3px;
cursor: pointer;
font-size: 12px;
}
.copy-button:hover {
background-color: #555;
}
/* 右键菜单样式 */
#context-menu {
position: absolute;
background-color: #252526;
border: 1px solid #444;
border-radius: 3px;
padding: 5px 0;
z-index: 1000;
}
#context-menu .menu-item {
padding: 8px 12px;
color: white;
cursor: pointer;
}
#context-menu .menu-item:hover {
background-color: #2a2d2e;
}
#chat-context {
margin-bottom: 10px;
}
#context-selector {
display: flex;
gap: 10px;
margin-bottom: 10px;
}
#context-list {
display: flex;
flex-wrap: wrap;
gap: 5px;
}
.context-item {
display: flex;
align-items: center;
background-color: #2a2d2e;
padding: 5px 10px;
border-radius: 3px;
font-size: 14px;
}
.context-item .remove-button {
margin-left: 10px;
cursor: pointer;
color: #ff6b6b;
}
.context-item .remove-button:hover {
color: #ff3b3b;
}
/* 模态框样式 */
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
background-color: #252526;
padding: 20px;
margin-left: calc((100vw - 400px) / 2);
margin-top: calc((100vh - 300px) / 2);
border-radius: 5px;
width: 400px;
max-height: 300px;
overflow-y: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.modal-header h3 {
margin: 0;
}
.modal-header button {
background: none;
border: none;
color: white;
font-size: 20px;
cursor: pointer;
}
.modal-body {
margin-bottom: 10px;
}
#editbtn {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
#editbtn button {
background-color: #0e639c;
margin: 0 4px;
color: white;
width: 100%;
border: none;
padding: 8px 12px;
border-radius: 3px;
cursor: pointer;
}
#chat-icon {
z-index: 111111;
}
#cancel-button {
text-align: center;
padding: 10px;
}
.cancel-btn {
background-color: #ff4444;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
transition: background-color 0.3s;
}
.cancel-btn:hover {
background-color: #cc0000;
}
.empty-project {
color: thistle;
text-align: center;
margin: 100px auto;
}
.now-project {
color: #2196F3;
text-align: center;
margin: 10px auto;
}
/* 添加提示框样式 */
#toast-container {
position: fixed;
top: 20px;
right: 20px;
z-index: 10000;
}
.toast {
min-width: 250px;
margin-bottom: 10px;
padding: 15px;
border-radius: 4px;
color: white;
font-size: 14px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
animation: slideIn 0.3s ease-in-out;
transition: opacity 0.3s ease-in-out;
}
.toast.success {
background-color: #4caf50;
}
.toast.error {
background-color: #f44336;
}
.toast.info {
background-color: #2196F3;
}
.toast.warning {
background-color: #ff9800;
}
@keyframes slideIn {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideOut {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(100%);
opacity: 0;
}
}
</style>
</head>
<body>
<div id="app">
<div class="maineditor">
<!-- 侧边栏 -->
<div id="sidebar">
<div class="edit-buttons" id="editbtn">
<button @click="openProject" v-show="!hasProject">open</button>
<button @click="createProject" v-show="!hasProject">create</button>
<button @click="closeProject" v-show="hasProject">close</button>
<button @click="refreshFileTree" v-show="hasProject">refresh</button>
</div>
<div v-if="nowproject!=''" class="now-project">now project:{{nowproject}}</div>
<div v-if="nowproject==''" class="empty-project">open or create</div>
<div id="file-tree" ref="fileTree"></div>
</div>
<!-- 编辑器区域 -->
<div id="editor">
<div id="tabs">
<div v-for="(tab, path) in tabs" :key="path" class="tab" :class="{ active: currentTab === path }"
@click="switchTab(path)">
<span><i v-if="tab.modified">*</i>{{ tab.name }}</span>
<span class="close-button" @click.stop="closeTab(path)">×</span>
</div>
</div>
<div id="code-editor-container" ref="editorContainer"></div>
<!-- <button @click="saveFile" v-show="currentTab">Save</button> -->
</div>
</div>
<!-- 聊天窗口 -->
<div id="chat-window" v-show="!chatMinimized" :style="chatWindowStyle">
<div id="chat-header" @mousedown="startDragging">
<span>AI Chat</span>
<div class="switch-label">
<span>Read-Only</span>
<label class="switch">
<input type="checkbox" v-model="readOnly">
<span class="slider"></span>
</label>
<span>Write</span>
</div>
<button @click="minimizeChat">−</button>
</div>
<div id="chat-body" ref="chatBody">
<div v-for="(message, index) in messages" :key="index" :class="['message', message.sender]"
v-html="renderMessage(message)">
</div>
</div>
<div id="chat-context">
<div id="context-selector" class="context-btn">
<span @click="showFileSelector">Add Context</span>
<span @click="clearContext">Clear All</span>
</div>
<div id="context-list">
<div v-for="(item, index) in selectedContext" :key="index" class="context-item">
<span :title="item.path">{{ item.path }}</span>
<span class="remove-button" @click="removeContext(index)">×</span>
</div>
</div>
</div>
<!-- 添加取消按钮 -->
<div id="cancel-button" v-if="isGenerating">
<button @click="cancelGeneration" class="cancel-btn">Stop Generating</button>
</div>
<div id="chat-input">
<textarea v-model="chatInput" @keydown.enter.prevent="sendMessage" placeholder="Type your message..."
:disabled="isGenerating">
</textarea>
</div>
</div>
<!-- 右键菜单 -->
<div id="context-menu" v-show="contextMenu.show" :style="{
position: 'fixed',
left: contextMenu.x + 'px',
top: contextMenu.y + 'px',
zIndex: 1000
}">
<div v-for="item in contextMenu.items" :key="item" class="menu-item" @click="handleContextMenuClick(item)">
{{ item.replace(/-/g, ' ') }}
</div>
</div>
<!-- 聊天图标 -->
<div id="chat-icon" v-show="chatMinimized" @click="showChat">
<img src="//repo.bfw.wiki/bfwrepo/icon/6413f21abdbea.png" alt="Chat Icon" width="50" height="50">
</div>
<!-- 文件选择模态框 -->
<div id="file-selector-modal" v-show="showFileSelectorModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3>Select Files</h3>
<button @click="closeFileSelector">×</button>
</div>
<div class="modal-body">
<div id="file-list">
<div v-for="file in availableFiles" :key="file.path" class="file-item"
:class="{ selected: isFileSelected(file) }" @click="toggleFileSelection(file)">
<input type="checkbox" :checked="isFileSelected(file)" @click.stop>
<span>{{ file.path }}</span>
</div>
</div>
</div>
<!-- <div class="modal-footer">
<button @click="confirmFileSelection">Confirm</button>
<button @click="closeFileSelector">Cancel</button>
</div> -->
</div>
</div>
<!-- 项目选择模态框 -->
<div id="project-selector-modal" v-show="showProjectModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3>Select Project</h3>
<button @click="closeProjectModal">×</button>
</div>
<div class="modal-body">
<div id="project-list">
<div v-for="project in projects" :key="project.path" class="project-item"
@click="selectProject(project)">
{{ project.path }}
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 在 body 末尾添加提示容器 -->
<div id="toast-container"></div>
<!-- CodeMirror and other scripts -->
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/vue@2.6.1-dev.js"></script>
<script src='//repo.bfw.wiki/bfwrepo/js/codemirror/codemirror.5.26.js'></script>
<script src='//repo.bfw.wiki/bfwrepo/js/codemirror/mode/xml/xml.js'></script>
<script src='//repo.bfw.wiki/bfwrepo/js/codemirror/mode/javascript/javascript.js'></script>
<script src='//repo.bfw.wiki/bfwrepo/js/codemirror/addon/edit/matchbrackets.js'></script>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/marked.umd.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
// 项目相关
nowproject: '',
hasProject: false,
projects: [],
.........完整代码请登录后点击上方下载按钮下载查看
网友评论0