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