Spaces:
No application file
No application file
<html><head><base href=""> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Carbon - Advanced Markdown Experience</title> | |
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&family=Orbitron:wght@700&display=swap" rel="stylesheet"> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css"> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/2.0.3/marked.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/codemirror.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/mode/markdown/markdown.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/edit/continuelist.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/edit/closebrackets.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/edit/matchbrackets.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/fold/foldcode.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/fold/foldgutter.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/fold/markdown-fold.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/hint/show-hint.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/hint/anyword-hint.min.js"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/codemirror.min.css"> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/fold/foldgutter.min.css"> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/hint/show-hint.min.css"> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.14.0/Sortable.min.js"></script> | |
<style> | |
:root { | |
--mint-green: #98ff98; | |
--pure-black: #000000; | |
--text-color: #e0e0e0; | |
} | |
body, html { | |
margin: 0; | |
padding: 0; | |
font-family: 'Inter', sans-serif; | |
background-color: var(--pure-black); | |
color: var(--text-color); | |
height: 100vh; | |
display: flex; | |
flex-direction: column; | |
overflow: hidden; | |
cursor: url('cursor.png'), auto; | |
} | |
.app-container { | |
display: flex; | |
flex: 1; | |
overflow: hidden; | |
user-select: none; | |
} | |
.sidebar { | |
width: 250px; | |
background-color: var(--pure-black); | |
border-right: 1px solid rgba(152, 255, 152, 0.2); | |
overflow-y: auto; | |
padding: 20px; | |
transition: width 0.3s ease; | |
} | |
.sidebar.hidden { | |
width: 0; | |
padding: 0; | |
border-right: none; | |
} | |
.file-explorer { | |
font-size: 14px; | |
} | |
.folder, .file { | |
margin: 5px 0; | |
cursor: pointer; | |
display: flex; | |
align-items: center; | |
padding: 5px; | |
border-radius: 4px; | |
transition: all 0.3s ease; | |
} | |
.folder:hover, .file:hover { | |
background-color: rgba(152, 255, 152, 0.1); | |
box-shadow: 0 0 15px rgba(152, 255, 152, 0.3); | |
transform: translateX(5px); | |
} | |
.folder::before, .file::before { | |
content: ''; | |
display: inline-block; | |
width: 16px; | |
height: 16px; | |
margin-right: 5px; | |
background-size: contain; | |
background-repeat: no-repeat; | |
transition: transform 0.3s ease; | |
} | |
.folder::before { | |
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%2398ff98"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></svg>'); | |
} | |
.file::before { | |
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%2398ff98"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/></svg>'); | |
} | |
.folder:hover::before, .file:hover::before { | |
transform: scale(1.2); | |
} | |
.folder-content { | |
margin-left: 15px; | |
display: none; | |
transition: all 0.3s ease; | |
} | |
.folder-content.open { | |
display: block; | |
} | |
.main-content { | |
flex: 1; | |
display: flex; | |
flex-direction: column; | |
overflow: hidden; | |
} | |
.header { | |
background-color: var(--pure-black); | |
padding: 15px; | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
box-shadow: 0 2px 20px rgba(152, 255, 152, 0.2); | |
position: relative; | |
overflow: hidden; | |
} | |
.logo { | |
font-family: 'Orbitron', sans-serif; | |
font-size: 28px; | |
font-weight: 700; | |
color: var(--mint-green); | |
text-shadow: 0 0 15px rgba(152, 255, 152, 0.7); | |
letter-spacing: 2px; | |
text-transform: uppercase; | |
transition: all 0.3s ease; | |
} | |
.logo:hover { | |
transform: scale(1.05); | |
text-shadow: 0 0 25px rgba(152, 255, 152, 0.9); | |
} | |
.editor-container { | |
flex: 1; | |
overflow: hidden; | |
position: relative; | |
transition: all 0.3s ease; | |
} | |
.CodeMirror { | |
height: 100% ; | |
font-family: 'Inter', monospace; | |
font-size: 16px; | |
background-color: var(--pure-black) ; | |
color: var(--text-color) ; | |
transition: all 0.3s ease; | |
} | |
.CodeMirror-gutters { | |
background-color: var(--pure-black) ; | |
border-right: 1px solid rgba(152, 255, 152, 0.2) ; | |
} | |
.CodeMirror-linenumber { | |
color: var(--mint-green) ; | |
} | |
.cm-header { | |
color: var(--mint-green) ; | |
font-weight: bold; | |
} | |
.cm-link { | |
color: #7abaff ; | |
} | |
.cm-url { | |
color: #ff9d9d ; | |
} | |
.cm-quote { | |
color: #b8ff7a ; | |
font-style: italic; | |
} | |
.cm-strong { | |
color: #fffa7a ; | |
font-weight: bold; | |
} | |
.cm-em { | |
color: #ff7af0 ; | |
font-style: italic; | |
} | |
.cm-code { | |
background-color: rgba(152, 255, 152, 0.1); | |
border-radius: 3px; | |
padding: 2px 4px; | |
} | |
.CodeMirror-cursor { | |
border-left: 2px solid var(--mint-green) ; | |
transition: all 0.1s ease; | |
} | |
.CodeMirror-selected { | |
background-color: rgba(152, 255, 152, 0.2) ; | |
} | |
::-webkit-scrollbar { | |
width: 8px; | |
height: 8px; | |
} | |
::-webkit-scrollbar-track { | |
background: var(--pure-black); | |
} | |
::-webkit-scrollbar-thumb { | |
background: var(--mint-green); | |
border-radius: 4px; | |
} | |
::-webkit-scrollbar-thumb:hover { | |
background: #7aff7a; | |
} | |
.context-menu { | |
position: fixed; | |
background-color: var(--pure-black); | |
border: 1px solid var(--mint-green); | |
border-radius: 4px; | |
padding: 10px 0; | |
z-index: 1000; | |
box-shadow: 0 0 20px rgba(152, 255, 152, 0.3); | |
transition: all 0.3s ease; | |
opacity: 0; | |
transform: scale(0.95); | |
pointer-events: none; | |
min-width: 200px; | |
} | |
.context-menu.active { | |
opacity: 1; | |
transform: scale(1); | |
pointer-events: all; | |
} | |
.context-menu-item { | |
padding: 12px 24px; | |
cursor: pointer; | |
transition: all 0.2s ease; | |
display: flex; | |
align-items: center; | |
font-size: 16px; | |
} | |
.context-menu-item:hover { | |
background-color: rgba(152, 255, 152, 0.2); | |
transform: translateX(5px); | |
} | |
.context-menu-item i { | |
margin-right: 12px; | |
font-size: 18px; | |
} | |
.loading-screen { | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background-color: var(--pure-black); | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
z-index: 1000; | |
transition: opacity 1s ease-out; | |
} | |
.loading-screen.fade-out { | |
opacity: 0; | |
pointer-events: none; | |
} | |
.loading-icon { | |
width: 100px; | |
height: 100px; | |
border: 5px solid var(--mint-green); | |
border-top: 5px solid var(--pure-black); | |
border-radius: 50%; | |
animation: spin 1s linear infinite, glow 2s ease-in-out infinite; | |
} | |
@keyframes spin { | |
0% { transform: rotate(0deg); } | |
100% { transform: rotate(360deg); } | |
} | |
@keyframes glow { | |
0%, 100% { box-shadow: 0 0 20px var(--mint-green); } | |
50% { box-shadow: 0 0 40px var(--mint-green); } | |
} | |
.dragging { | |
opacity: 0.5; | |
} | |
.drag-over { | |
background-color: rgba(152, 255, 152, 0.2); | |
} | |
.button { | |
background-color: transparent; | |
color: var(--mint-green); | |
border: none; | |
padding: 10px; | |
border-radius: 5px; | |
cursor: pointer; | |
font-size: 20px; | |
transition: all 0.3s ease; | |
margin-left: 10px; | |
position: relative; | |
overflow: hidden; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
} | |
.button::before { | |
content: ''; | |
position: absolute; | |
top: -50%; | |
left: -50%; | |
width: 200%; | |
height: 200%; | |
background: radial-gradient(circle, rgba(255, 255, 255, 0.3) 0%, transparent 70%); | |
transform: translate(-50%, -50%); | |
opacity: 0; | |
transition: opacity 0.3s ease; | |
} | |
.button:hover::before { | |
opacity: 1; | |
animation: buttonGlow 2s infinite linear; | |
} | |
@keyframes buttonGlow { | |
0% { transform: translate(-50%, -50%) rotate(0deg); } | |
100% { transform: translate(-50%, -50%) rotate(360deg); } | |
} | |
.button:hover { | |
color: #7aff7a; | |
box-shadow: 0 0 15px rgba(152, 255, 152, 0.7); | |
transform: translateY(-2px); | |
} | |
.button:active { | |
transform: scale(0.95) translateY(0); | |
} | |
.modal-overlay { | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background-color: rgba(0, 0, 0, 0.7); | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
z-index: 1000; | |
opacity: 0; | |
visibility: hidden; | |
transition: opacity 0.3s ease, visibility 0.3s ease; | |
} | |
.modal-overlay.active { | |
opacity: 1; | |
visibility: visible; | |
} | |
.modal-content { | |
background-color: var(--pure-black); | |
border: 2px solid var(--mint-green); | |
border-radius: 10px; | |
padding: 40px; | |
text-align: center; | |
box-shadow: 0 0 30px rgba(152, 255, 152, 0.5); | |
transform: scale(0.8); | |
transition: all 0.3s ease; | |
width: 500px; | |
} | |
.modal-overlay.active .modal-content { | |
transform: scale(1); | |
} | |
.modal-title { | |
font-size: 32px; | |
color: var(--mint-green); | |
margin-bottom: 30px; | |
text-shadow: 0 0 10px rgba(152, 255, 152, 0.5); | |
} | |
.modal-input { | |
width: 100%; | |
padding: 15px; | |
margin-bottom: 30px; | |
background-color: rgba(152, 255, 152, 0.1); | |
border: 1px solid var(--mint-green); | |
border-radius: 5px; | |
color: var(--text-color); | |
font-size: 18px; | |
transition: all 0.3s ease; | |
} | |
.modal-input:focus { | |
outline: none; | |
box-shadow: 0 0 15px rgba(152, 255, 152, 0.5); | |
background-color: rgba(152, 255, 152, 0.2); | |
} | |
.modal-buttons { | |
display: flex; | |
justify-content: center; | |
gap: 20px; | |
margin-top: 30px; | |
} | |
.modal-button { | |
background-color: var(--mint-green); | |
color: var(--pure-black); | |
border: none; | |
padding: 15px 30px; | |
border-radius: 5px; | |
cursor: pointer; | |
font-weight: bold; | |
transition: all 0.3s ease; | |
font-size: 18px; | |
} | |
.modal-button:hover { | |
background-color: #7aff7a; | |
box-shadow: 0 0 15px rgba(152, 255, 152, 0.7); | |
transform: translateY(-2px); | |
} | |
.modal-button:active { | |
transform: translateY(0); | |
} | |
.modal-button.cancel { | |
background-color: transparent; | |
color: var(--mint-green); | |
border: 2px solid var(--mint-green); | |
} | |
.modal-button.cancel:hover { | |
background-color: rgba(152, 255, 152, 0.2); | |
} | |
.selected { | |
background-color: rgba(152, 255, 152, 0.2); | |
box-shadow: 0 0 10px rgba(152, 255, 152, 0.5); | |
} | |
@keyframes cursorPulse { | |
0% { opacity: 0; } | |
50% { opacity: 1; } | |
100% { opacity: 0; } | |
} | |
.CodeMirror-cursors { | |
transition: all 0.1s ease; | |
} | |
.CodeMirror-cursor { | |
border-left: none ; | |
width: 2px; | |
background-color: var(--mint-green); | |
box-shadow: 0 0 5px var(--mint-green); | |
animation: cursorPulse 1.5s ease-in-out infinite; | |
} | |
.copy-notification { | |
position: fixed; | |
bottom: 20px; | |
right: 20px; | |
background-color: var(--mint-green); | |
color: var(--pure-black); | |
padding: 10px 20px; | |
border-radius: 5px; | |
font-weight: bold; | |
opacity: 0; | |
transform: translateY(20px); | |
transition: all 0.3s ease; | |
} | |
.copy-notification.show { | |
opacity: 1; | |
transform: translateY(0); | |
} | |
#toggleSidebarButton { | |
background-color: transparent; | |
border: none; | |
color: var(--mint-green); | |
cursor: pointer; | |
font-size: 20px; | |
transition: all 0.3s ease; | |
margin-right: 10px; | |
} | |
#toggleSidebarButton:hover { | |
transform: scale(1.2); | |
text-shadow: 0 0 10px rgba(152, 255, 152, 0.7); | |
} | |
.preview-container { | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background-color: rgba(0, 0, 0, 0.8); | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
z-index: 1000; | |
opacity: 0; | |
visibility: hidden; | |
transition: opacity 0.3s ease, visibility 0.3s ease; | |
} | |
.preview-container.active { | |
opacity: 1; | |
visibility: visible; | |
} | |
.preview-content { | |
background-color: var(--pure-black); | |
border: 2px solid var(--mint-green); | |
border-radius: 10px; | |
padding: 40px; | |
width: 80%; | |
height: 80%; | |
overflow-y: auto; | |
box-shadow: 0 0 30px rgba(152, 255, 152, 0.5); | |
} | |
.preview-close { | |
position: absolute; | |
top: 20px; | |
right: 20px; | |
background-color: transparent; | |
border: none; | |
color: var(--mint-green); | |
font-size: 24px; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
} | |
.preview-close:hover { | |
transform: scale(1.2); | |
text-shadow: 0 0 10px rgba(152, 255, 152, 0.7); | |
} | |
.markdown-body { | |
color: var(--text-color); | |
} | |
.markdown-body h1, | |
.markdown-body h2, | |
.markdown-body h3, | |
.markdown-body h4, | |
.markdown-body h5, | |
.markdown-body h6 { | |
color: var(--mint-green); | |
} | |
.markdown-body a { | |
color: #7abaff; | |
} | |
.markdown-body code { | |
background-color: rgba(152, 255, 152, 0.1); | |
color: #ff9d9d; | |
} | |
.markdown-body pre { | |
background-color: rgba(152, 255, 152, 0.05); | |
border: 1px solid rgba(152, 255, 152, 0.2); | |
} | |
.markdown-body blockquote { | |
border-left-color: var(--mint-green); | |
color: #b8ff7a; | |
} | |
.modal-overlay { | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background-color: rgba(0, 0, 0, 0.8); | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
z-index: 1000; | |
opacity: 0; | |
visibility: hidden; | |
transition: opacity 0.3s ease, visibility 0.3s ease; | |
} | |
.modal-overlay.active { | |
opacity: 1; | |
visibility: visible; | |
} | |
.modal-content { | |
background-color: var(--pure-black); | |
border: 2px solid var(--mint-green); | |
border-radius: 15px; | |
padding: 40px; | |
width: 400px; | |
max-width: 90%; | |
text-align: center; | |
box-shadow: 0 0 30px rgba(152, 255, 152, 0.5); | |
transform: scale(0.9); | |
transition: all 0.3s ease; | |
} | |
.modal-overlay.active .modal-content { | |
transform: scale(1); | |
} | |
.modal-title { | |
font-size: 28px; | |
color: var(--mint-green); | |
margin-bottom: 20px; | |
text-shadow: 0 0 10px rgba(152, 255, 152, 0.5); | |
} | |
.modal-input { | |
width: 100%; | |
padding: 12px; | |
margin-bottom: 20px; | |
background-color: rgba(152, 255, 152, 0.1); | |
border: 1px solid var(--mint-green); | |
border-radius: 5px; | |
color: var(--text-color); | |
font-size: 16px; | |
transition: all 0.3s ease; | |
} | |
.modal-input:focus { | |
outline: none; | |
box-shadow: 0 0 15px rgba(152, 255, 152, 0.5); | |
background-color: rgba(152, 255, 152, 0.2); | |
} | |
.modal-buttons { | |
display: flex; | |
justify-content: center; | |
gap: 15px; | |
} | |
.modal-button { | |
background-color: var(--mint-green); | |
color: var(--pure-black); | |
border: none; | |
padding: 12px 24px; | |
border-radius: 5px; | |
cursor: pointer; | |
font-weight: bold; | |
transition: all 0.3s ease; | |
font-size: 16px; | |
} | |
.modal-button:hover { | |
background-color: #7aff7a; | |
box-shadow: 0 0 15px rgba(152, 255, 152, 0.7); | |
transform: translateY(-2px); | |
} | |
.modal-button:active { | |
transform: translateY(0); | |
} | |
.modal-button.cancel { | |
background-color: transparent; | |
color: var(--mint-green); | |
border: 2px solid var(--mint-green); | |
} | |
.modal-button.cancel:hover { | |
background-color: rgba(152, 255, 152, 0.2); | |
} | |
</style> | |
</head> | |
<body> | |
<div class="loading-screen"> | |
<div class="loading-icon"></div> | |
</div> | |
<div class="app-container"> | |
<div class="sidebar" id="sidebar"> | |
<div class="file-explorer" id="fileExplorer"></div> | |
</div> | |
<div class="main-content"> | |
<div class="header"> | |
<button id="toggleSidebarButton" class="button"><i class="fas fa-bars"></i></button> | |
<div class="logo">Carbon</div> | |
<div> | |
<button id="previewButton" class="button" title="Preview"><i class="fas fa-eye"></i></button> | |
<button id="importButton" class="button" title="Import"><i class="fas fa-file-import"></i></button> | |
<button id="exportButton" class="button" title="Export"><i class="fas fa-file-export"></i></button> | |
</div> | |
</div> | |
<div class="editor-container"> | |
<textarea id="editor"></textarea> | |
</div> | |
</div> | |
</div> | |
<div class="modal-overlay" id="renameModal"> | |
<div class="modal-content"> | |
<h2 class="modal-title">Rename Item</h2> | |
<input type="text" id="renameInput" class="modal-input" placeholder="Enter new name"> | |
<div class="modal-buttons"> | |
<button class="modal-button cancel" id="cancelRename">Cancel</button> | |
<button class="modal-button" id="confirmRename">Rename</button> | |
</div> | |
</div> | |
</div> | |
<div class="modal-overlay" id="deleteModal"> | |
<div class="modal-content"> | |
<h2 class="modal-title">Confirm Deletion</h2> | |
<p>Are you sure you want to delete this item?</p> | |
<div class="modal-buttons"> | |
<button class="modal-button cancel" id="cancelDelete">Cancel</button> | |
<button class="modal-button" id="confirmDelete">Delete</button> | |
</div> | |
</div> | |
</div> | |
<div class="modal-overlay" id="newFileModal"> | |
<div class="modal-content"> | |
<h2 class="modal-title">Create New File</h2> | |
<input type="text" id="newFileInput" class="modal-input" placeholder="Enter file name"> | |
<div class="modal-buttons"> | |
<button class="modal-button cancel" id="cancelNewFile">Cancel</button> | |
<button class="modal-button" id="confirmNewFile">Create</button> | |
</div> | |
</div> | |
</div> | |
<div class="modal-overlay" id="newFolderModal"> | |
<div class="modal-content"> | |
<h2 class="modal-title">Create New Folder</h2> | |
<input type="text" id="newFolderInput" class="modal-input" placeholder="Enter folder name"> | |
<div class="modal-buttons"> | |
<button class="modal-button cancel" id="cancelNewFolder">Cancel</button> | |
<button class="modal-button" id="confirmNewFolder">Create</button> | |
</div> | |
</div> | |
</div> | |
<div class="preview-container" id="previewContainer"> | |
<div class="preview-content markdown-body" id="previewContent"></div> | |
<button class="preview-close" id="previewClose"><i class="fas fa-times"></i></button> | |
</div> | |
<div class="copy-notification" id="copyNotification">Copied!</div> | |
<input type="file" id="fileInput" style="display: none;" accept=".md"> | |
<script> | |
// File system structure | |
let fileSystem = { | |
'Documents': { | |
'readme.md': '# test' | |
} | |
}; | |
// Function to create file explorer HTML | |
function createFileExplorer(structure, path = '') { | |
let html = '<ul class="sortable-list">'; | |
for (const [name, content] of Object.entries(structure)) { | |
const fullPath = path ? `${path}/${name}` : name; | |
if (typeof content === 'object') { | |
html += `<li> | |
<div class="folder" data-path="${fullPath}">${name}</div> | |
<div class="folder-content">${createFileExplorer(content, fullPath)}</div> | |
</li>`; | |
} else { | |
html += `<li><div class="file" data-path="${fullPath}">${name}</div></li>`; | |
} | |
} | |
html += '</ul>'; | |
return html; | |
} | |
// Initialize CodeMirror | |
const editor = CodeMirror.fromTextArea(document.getElementById('editor'), { | |
mode: 'markdown', | |
theme: 'monokai', | |
lineNumbers: true, | |
lineWrapping: true, | |
autofocus: true, | |
indentUnit: 4, | |
tabSize: 4, | |
indentWithTabs: true, | |
extraKeys: { | |
"Enter": "newlineAndIndentContinueMarkdownList", | |
"Ctrl-Space": "autocomplete" | |
}, | |
autoCloseBrackets: true, | |
matchBrackets: true, | |
foldGutter: true, | |
gutters: ["Code Mirror-linenumbers", "CodeMirror-foldgutter"], | |
hintOptions: { | |
completeSingle: false | |
} | |
}); | |
// Function to update editor content | |
function updateEditorContent(path) { | |
const content = getFileContent(path); | |
editor.setValue(content); | |
editor.clearHistory(); | |
} | |
// Function to get file content | |
function getFileContent(path) { | |
const parts = path.split('/'); | |
let current = fileSystem; | |
for (const part of parts) { | |
if (current[part] === undefined) { | |
return ''; | |
} | |
current = current[part]; | |
} | |
return typeof current === 'string' ? current : ''; | |
} | |
// Function to set file content | |
function setFileContent(path, content) { | |
const parts = path.split('/'); | |
let current = fileSystem; | |
for (let i = 0; i < parts.length - 1; i++) { | |
if (current[parts[i]] === undefined) { | |
current[parts[i]] = {}; | |
} | |
current = current[parts[i]]; | |
} | |
current[parts[parts.length - 1]] = content; | |
} | |
// Function to render file explorer | |
function renderFileExplorer() { | |
const fileExplorer = document.getElementById('fileExplorer'); | |
fileExplorer.innerHTML = createFileExplorer(fileSystem); | |
initializeSortable(); | |
} | |
// Initialize sortable functionality | |
function initializeSortable() { | |
const sortableLists = document.querySelectorAll('.sortable-list'); | |
sortableLists.forEach(list => { | |
new Sortable(list, { | |
group: 'nested', | |
animation: 150, | |
fallbackOnBody: true, | |
swapThreshold: 0.65, | |
onEnd: function (evt) { | |
const item = evt.item; | |
const from = evt.from; | |
const to = evt.to; | |
const oldPath = item.querySelector('.file, .folder').getAttribute('data-path'); | |
const newParentPath = to.closest('.folder-content')?.previousElementSibling?.getAttribute('data-path') || ''; | |
const newPath = newParentPath ? `${newParentPath}/${item.textContent}` : item.textContent; | |
if (oldPath !== newPath) { | |
moveItem(oldPath, newPath); | |
renderFileExplorer(); | |
} | |
} | |
}); | |
}); | |
} | |
// Function to move an item in the file system | |
function moveItem(oldPath, newPath) { | |
const content = getFileContent(oldPath); | |
deleteItem(oldPath); | |
setFileContent(newPath, content); | |
} | |
// Function to delete an item from the file system | |
function deleteItem(path) { | |
const parts = path.split('/'); | |
let current = fileSystem; | |
for (let i = 0; i < parts.length - 1; i++) { | |
if (current[parts[i]] === undefined) { | |
return; | |
} | |
current = current[parts[i]]; | |
} | |
delete current[parts[parts.length - 1]]; | |
} | |
// Event listener for file explorer clicks | |
document.getElementById('fileExplorer').addEventListener('click', function(e) { | |
const target = e.target; | |
if (target.classList.contains('file')) { | |
const path = target.getAttribute('data-path'); | |
updateEditorContent(path); | |
document.querySelectorAll('.file, .folder').forEach(el => el.classList.remove('selected')); | |
target.classList.add('selected'); | |
} else if (target.classList.contains('folder')) { | |
target.classList.toggle('open'); | |
const content = target.nextElementSibling; | |
if (content) { | |
content.classList.toggle('open'); | |
} | |
} | |
}); | |
// Event listener for editor changes | |
editor.on('change', function() { | |
const selectedFile = document.querySelector('.file.selected'); | |
if (selectedFile) { | |
const path = selectedFile.getAttribute('data-path'); | |
setFileContent(path, editor.getValue()); | |
} | |
}); | |
// Initialize file explorer | |
renderFileExplorer(); | |
// Function to show modal | |
function showModal(modalId) { | |
document.getElementById(modalId).classList.add('active'); | |
} | |
// Function to hide modal | |
function hideModal(modalId) { | |
document.getElementById(modalId).classList.remove('active'); | |
} | |
// Context menu functionality | |
const contextMenu = document.createElement('div'); | |
contextMenu.className = 'context-menu'; | |
contextMenu.innerHTML = ` | |
<div class="context-menu-item" id="renameItem"><i class="fas fa-edit"></i>Rename</div> | |
<div class="context-menu-item" id="deleteItem"><i class="fas fa-trash-alt"></i>Delete</div> | |
<div class="context-menu-item" id="newFile"><i class="fas fa-file"></i>New File</div> | |
<div class="context-menu-item" id="newFolder"><i class="fas fa-folder"></i>New Folder</div> | |
`; | |
document.body.appendChild(contextMenu); | |
let contextMenuTarget = null; | |
document.addEventListener('contextmenu', function(e) { | |
if (e.target.classList.contains('file') || e.target.classList.contains('folder')) { | |
e.preventDefault(); | |
contextMenuTarget = e.target; | |
contextMenu.style.top = `${e.clientY}px`; | |
contextMenu.style.left = `${e.clientX}px`; | |
contextMenu.classList.add('active'); | |
} | |
}); | |
document.addEventListener('click', function() { | |
contextMenu.classList.remove('active'); | |
}); | |
// Rename functionality | |
document.getElementById('renameItem').addEventListener('click', function() { | |
if (contextMenuTarget) { | |
showModal('renameModal'); | |
document.getElementById('renameInput').value = contextMenuTarget.textContent; | |
} | |
}); | |
document.getElementById('confirmRename').addEventListener('click', function() { | |
const newName = document.getElementById('renameInput').value; | |
if (newName && contextMenuTarget) { | |
const oldPath = contextMenuTarget.getAttribute('data-path'); | |
const newPath = oldPath.split('/').slice(0, -1).concat(newName).join('/'); | |
moveItem(oldPath, newPath); | |
renderFileExplorer(); | |
hideModal('renameModal'); | |
} | |
}); | |
document.getElementById('cancelRename').addEventListener('click', function() { | |
hideModal('renameModal'); | |
}); | |
// Delete functionality | |
document.getElementById('deleteItem').addEventListener('click', function() { | |
if (contextMenuTarget) { | |
showModal('deleteModal'); | |
} | |
}); | |
document.getElementById('confirmDelete').addEventListener('click', function() { | |
if (contextMenuTarget) { | |
const path = contextMenuTarget.getAttribute('data-path'); | |
deleteItem(path); | |
renderFileExplorer(); | |
hideModal('deleteModal'); | |
} | |
}); | |
document.getElementById('cancelDelete').addEventListener('click', function() { | |
hideModal('deleteModal'); | |
}); | |
// New file functionality | |
document.getElementById('newFile').addEventListener('click', function() { | |
showModal('newFileModal'); | |
}); | |
document.getElementById('confirmNewFile').addEventListener('click', function() { | |
const fileName = document.getElementById('newFileInput').value; | |
if (fileName) { | |
const parentPath = contextMenuTarget.getAttribute('data-path'); | |
const newPath = parentPath ? `${parentPath}/${fileName}.md` : `${fileName}.md`; | |
setFileContent(newPath, ''); | |
renderFileExplorer(); | |
hideModal('newFileModal'); | |
} | |
}); | |
document.getElementById('cancelNewFile').addEventListener('click', function() { | |
hideModal('newFileModal'); | |
}); | |
// New folder functionality | |
document.getElementById('newFolder').addEventListener('click', function() { | |
showModal('newFolderModal'); | |
}); | |
document.getElementById('confirmNewFolder').addEventListener('click', function() { | |
const folderName = document.getElementById('newFolderInput').value; | |
if (folderName) { | |
const parentPath = contextMenuTarget.getAttribute('data-path'); | |
const newPath = parentPath ? `${parentPath}/${folderName}` : folderName; | |
setFileContent(newPath, {}); | |
renderFileExplorer(); | |
hideModal('newFolderModal'); | |
} | |
}); | |
document.getElementById('cancelNewFolder').addEventListener('click', function() { | |
hideModal('newFolderModal'); | |
}); | |
// Toggle sidebar functionality | |
document.getElementById('toggleSidebarButton').addEventListener('click', function() { | |
document.getElementById('sidebar').classList.toggle('hidden'); | |
}); | |
// Preview functionality | |
document.getElementById('previewButton').addEventListener('click', function() { | |
const content = editor.getValue(); | |
const renderedContent = marked(content); | |
document.getElementById('previewContent').innerHTML = renderedContent; | |
document.getElementById('previewContainer').classList.add('active'); | |
}); | |
document.getElementById('previewClose').addEventListener('click', function() { | |
document.getElementById('previewContainer').classList.remove('active'); | |
}); | |
// Import functionality | |
document.getElementById('importButton').addEventListener('click', function() { | |
document.getElementById('fileInput').click(); | |
}); | |
document.getElementById('fileInput').addEventListener('change', function(e) { | |
const file = e.target.files[0]; | |
if (file) { | |
const reader = new FileReader(); | |
reader.onload = function(e) { | |
const content = e.target.result; | |
setFileContent(file.name, content); | |
renderFileExplorer(); | |
}; | |
reader.readAsText(file); | |
} | |
}); | |
// Export functionality | |
document.getElementById('exportButton').addEventListener('click', function() { | |
const selectedFile = document.querySelector('.file.selected'); | |
if (selectedFile) { | |
const fileName = selectedFile.textContent; | |
const content = editor.getValue(); | |
const blob = new Blob([content], {type: 'text/markdown'}); | |
const url = URL.createObjectURL(blob); | |
const a = document.createElement('a'); | |
a.href = url; | |
a.download = fileName; | |
a.click(); | |
URL.revokeObjectURL(url); | |
} | |
}); | |
// Copy to clipboard functionality | |
editor.on('copy', function(cm, e) { | |
if (e.clipboardData) { | |
e.clipboardData.setData('text/plain', cm.getSelection()); | |
e.preventDefault(); | |
showCopyNotification(); | |
} | |
}); | |
function showCopyNotification() { | |
const notification = document.getElementById('copyNotification'); | |
notification.classList.add('show'); | |
setTimeout(() => { | |
notification.classList.remove('show'); | |
}, 2000); | |
} | |
// Loading screen | |
window.addEventListener('load', function() { | |
setTimeout(() => { | |
document.querySelector('.loading-screen').classList.add('fade-out'); | |
}, 1000); | |
}); | |
</script> | |
</body> | |
</html> |