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)">&times;</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">&times;</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">&times;</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